Mockito测试问题:测试One类method1时如何模拟Two类的method3方法
问题原因分析
你遇到的核心问题是:你测试代码里创建的spy two和One类内部实际持有的two是完全不同的对象。
看一下One的构造函数:它是自己直接new Two(this)生成了内部的two实例,而你在setup里创建的spy two并没有被One使用到,所以你对这个spy two的method3做的模拟自然不会生效。而method2能被成功模拟,是因为它属于你创建的spy one对象本身,调用的是同一个实例的方法。
解决方案
下面提供两种可行的解决思路,优先推荐第一种(代码重构),如果不能修改原代码再用第二种反射方案。
方案1:重构代码,使用依赖注入(推荐)
把Two的实例通过构造函数注入到One中,而不是让One自己创建Two,这样测试时可以直接传入Mock的Two实例。
修改原代码
class One { private final Two two; // 改为构造注入Two,而不是内部new public One(Two two) { this.two = two; } public void method1() { //do something method2(); } public void method2() { //do something two.method3(); } } class Two { private final One one; public Two(One one) { this.one = one; } public void method3() { //print something } }
对应的JUnit测试代码
import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import static org.mockito.Mockito.*; public class OneTest { @Mock private Two mockTwo; private One one; @Before public void setup() { MockitoAnnotations.openMocks(this); // 把Mock的Two传入One的构造函数 one = new One(mockTwo); } @Test public void testMethod1InClassOne() { // 模拟method3什么都不做 doNothing().when(mockTwo).method3(); one.method1(); // 验证method3是否被调用了一次(可选,确保逻辑符合预期) verify(mockTwo, times(1)).method3(); } }
方案2:用反射替换One内部的two字段(无需修改原代码)
如果因为各种原因不能修改原业务代码,我们可以通过反射机制,把One内部私有的two字段替换成我们的Mock实例。
测试代码示例
import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.lang.reflect.Field; import static org.mockito.Mockito.*; public class OneTest { private One one; @Mock private Two mockTwo; @Before public void setup() { MockitoAnnotations.openMocks(this); one = new One(); // 通过反射替换One内部的two字段 try { Field twoField = One.class.getDeclaredField("two"); twoField.setAccessible(true); // 允许访问私有字段 twoField.set(one, mockTwo); // 替换为Mock实例 } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } } @Test public void testMethod1InClassOne() { doNothing().when(mockTwo).method3(); one.method1(); verify(mockTwo).method3(); } }
这样修改后,One内部调用的two.method3()就会是我们Mock的实例,模拟逻辑就能生效了。
内容的提问来源于stack exchange,提问作者Meher M
相关产品推荐
相关产品推荐

