为何部分@Mock对象未关联Mockito拦截器?
关于Mockito模拟对象拦截器差异的问题解答
核心结论
- 模拟接口 vs 模拟类的拦截器差异:Mockito针对接口和类的实现机制不同——模拟接口时,Mockito会直接生成实现该接口的JDK代理类(带明确拦截器);而模拟类时,默认使用CGLIB/ByteBuddy动态生成子类,这类模拟对象不会显示
$MockitoMock$标识,调试时也看不到直观的“拦截器”结构,但底层依然由Mockito接管方法调用。你看到的“拦截器缺失”只是实现细节的表象,并非真的没有Mockito逻辑介入。 - 拦截器表象不影响存根(Stubbing):只要模拟对象是通过
@Mock注解+openMocks(this)正确初始化的,不管是接口还是类的模拟,都能正常进行方法存根和调用验证。
针对你无法工作的测试代码的修复
你的第一个测试代码失效,核心原因不是拦截器问题,而是未将模拟对象注入被测类,且测试中使用了真实实例而非模拟对象。修复后的代码如下:
public class FooTest { // 修正类名规范:首字母大写 @InjectMocks // 让Mockito自动将@Mock对象注入被测类实例 ClassInTest classInTest; AutoCloseable mocks; @Mock Animal animal; // 模拟接口 @Mock Bike vehicle; // 模拟类 @Before public void init() { mocks = openMocks(this); // 初始化所有@Mock和@InjectMocks对象 } @After public void teardown() throws Exception { mocks.close(); } @Test public void dogRidesBikeTest() { // 对模拟对象进行存根(接口/类模拟均生效) when(animal.getName()).thenReturn("Mocked Dog"); when(vehicle.doSomething()).thenReturn("Mocked Bike Action"); // 传入模拟对象到被测方法,而非真实实例 boolean result = classInTest.checkIfAnimalRidesVehicle(animal, vehicle); // 验证模拟方法的调用情况 verify(vehicle).doSomething(); assertEquals(false, result); // 验证返回值 } }
修复关键点
- 添加
@InjectMocks注解声明被测类实例,让Mockito自动完成依赖注入; - 测试方法中传入
@Mock创建的模拟对象,而非真实的Dog、Bike实例; - 接口和类的模拟对象均可正常使用
when().thenReturn()进行存根,以及verify()进行调用验证。
额外说明
你观察到的“部分模拟对象无拦截器”是Mockito的实现细节:
- 接口模拟:基于JDK动态代理,生成带有
$MockitoMock$后缀的代理类,调试时能看到明确的拦截器结构; - 类模拟:基于字节码增强技术生成子类,调试时无明显拦截器标识,但Mockito会拦截所有非final方法的调用。只要模拟对象初始化流程正确,完全不影响测试逻辑。
内容的提问来源于stack exchange,提问作者flair
相关产品推荐
相关产品推荐

