Mockito:Mock类构造函数并调用真实方法的单元测试问题
解决类A单元测试时跳过构造函数中getB()调用的方案
首先纠正原代码里的一处编译错误:类A的构造函数中变量名应为小写的b,原代码写成了大写B,修正后如下:
public A() { b = getB(); }
针对你的需求——不执行构造函数内的getB()调用,同时测试doSomething()的真实逻辑,提供以下几种可行方案:
方案1:创建A的测试子类重写getB()
利用Java继承特性,创建A的匿名子类并重写getB()方法,直接返回mock的B实例,让构造函数调用getB()时跳过原逻辑:
@Test class TestA { @Mock B b; private A a; @BeforeMethod public void beforeMethod() { MockitoAnnotations.openMocks(this); // 创建A的子类,重写getB()返回mock对象 a = new A() { @Override B getB() { return b; } }; } @Test public void testMethod() { // 预设mock方法的返回值 doReturn("预期结果").when(b).doOtherThing(); // 执行真实的doSomething()方法 a.doSomething(); // 验证mock方法被调用 verify(b).doOtherThing(); } }
方案2:使用Mockito的CALLS_REAL_METHODS创建Mock并手动注入字段
通过创建A的Mock实例并指定调用真实方法,再通过反射将mock的B注入到A的b字段,完全绕过构造函数中的getB()调用:
import java.lang.reflect.Field; import org.mockito.Mockito; @Test class TestA { @Mock B b; private A a; @BeforeMethod public void beforeMethod() throws NoSuchFieldException, IllegalAccessException { MockitoAnnotations.openMocks(this); // 创建A的Mock实例,指定调用真实方法 a = Mockito.mock(A.class, Mockito.CALLS_REAL_METHODS); // 通过反射设置A的b字段为mock对象 Field bField = A.class.getDeclaredField("b"); bField.setAccessible(true); bField.set(a, b); } @Test public void testMethod() { doReturn("预期结果").when(b).doOtherThing(); a.doSomething(); verify(b).doOtherThing(); } }
方案3:结合@Spy与doReturn提前拦截getB()
使用@Spy时默认会调用真实构造函数,需要在构造实例前预设getB()的返回值,确保构造函数调用时使用mock对象:
@Test class TestA { @Mock B b; private A a; @BeforeMethod public void beforeMethod() { MockitoAnnotations.openMocks(this); // 先创建Spy实例,预设getB()返回mock对象 a = Mockito.spy(A.class); Mockito.doReturn(b).when(a).getB(); // 重新初始化实例,确保构造函数调用getB()时用预设返回值 a = new A(); } @Test public void testMethod() { doReturn("预期结果").when(b).doOtherThing(); a.doSomething(); verify(b).doOtherThing(); } }
方案说明
- 方案1最简单直观,无需依赖反射或特殊配置,适合大多数常规场景;
- 方案2完全绕过原构造函数逻辑,适合
getB()逻辑复杂或无法通过子类重写的场景; - 方案3保留A的真实方法实现,同时精准拦截指定方法调用,兼顾灵活性和真实性。
内容的提问来源于stack exchange,提问作者Mohamed Hafidi
相关产品推荐
相关产品推荐

