Mockito实战避坑指南:嵌套依赖与when/doReturn的正确姿势
在近期针对SpringBoot组件的单元测试中,我们遭遇了两个典型的Mockito使用陷阱。本文将复盘核心问题及解决方案,帮助大家绕开同类坑点。(耗时4小时的教训总结)
一、嵌套Mock的生存法则
当测试对象存在多层级依赖注入时(如A依赖B,B依赖C),直接使用@Mock
进行链式mock会导致空指针异常。通过Stack Overflow高赞方案验证,推荐采用组合拳:
// 二级依赖对象
@Spy
private MockObject1 mockObject1 = new MockObject1();
// 一级依赖对象(自动注入二级依赖)
@InjectMocks
private MockObject2 mockObject2 = spy(MockObject2.class);
// 被测对象(自动注入一级依赖)
@InjectMocks
private SystemUnderTest systemUnderTest;
实现原理:
@InjectMocks
会递归解析被修饰对象的成员变量,配合spy()
实现对部分方法的真实调用。这种方案比纯Mock方案更贴近真实调用链路。
二、when()与doReturn()的致命差异
Mockito的这两个API存在关键行为差异:
场景 | 推荐写法 | 注意事项 |
---|---|---|
普通@Mock对象 | when().thenReturn() | 等价于doReturn写法 |
@Spy监控的真实对象 | doReturn().when() | 避免执行真实方法,特别适用于void方法或异常场景 |
错误案例警示:
// 对spy对象使用when()会导致真实方法被调用!
// 引发真实调用
when(spyService.criticalOperation()).thenReturn(fakeData);
// 正确写法应阻断实际调用
doReturn(fakeData).when(spyService).criticalOperation();
经验总结
-
谨慎使用嵌套Mock,必要时通过
@InjectMocks+spy()
实现部分模拟 -
区分测试替身类型,@Spy对象必须使用doReturn规避副作用
-
复杂场景建议配合Mockito的
verify()
进行行为验证
本文解决方案参考:
Multiple levels of @Mock and @InjectMocks
mockito-difference-between-doreturn-and-when