
当使用 @InjectMocks 自动注入被测类时,若其依赖的字段(如 ServiceClass)已被 @Mock 声明,Mockito 会跳过真实依赖注入逻辑,导致深层依赖(如 UtilsClass)仍为 null,引发 NullPointerException。正确做法是改用 @Mock 直接模拟被测类本身,并手动控制行为。
当使用 `@injectmocks` 自动注入被测类时,若其依赖的字段(如 `serviceclass`)已被 `@mock` 声明,mockito 会跳过真实依赖注入逻辑,导致深层依赖(如 `utilsclass`)仍为 null,引发 nullpointerexception。正确做法是改用 `@mock` 直接模拟被测类本身,并手动控制行为。
在 Mockito 测试中,@InjectMocks 的设计初衷是自动将标注为 @Mock 或 @Spy 的依赖注入到被测对象中,并调用其构造器或 setter 方法创建真实实例。但该机制存在关键限制:它不会递归初始化依赖对象的内部依赖。例如,在你的代码中:
-
FileService依赖ServiceClass(已@Mock); -
ServiceClass又依赖UtilsClass(也@Mock),但@InjectMocks并不会将utilsClass注入到serviceClass实例中——因为serviceClass是一个纯 mock 对象,其字段默认为null。
因此,当执行 when(serviceClass.method_service_class()).thenCallRealMethod() 时,serviceClass 虽然调用了真实方法,但其中 utilsClass.method() 仍访问的是 null 引用,从而抛出 NullPointerException。
✅ 正确解决方案:避免对被测类使用 @InjectMocks,改用 @Mock + @Spy 组合或直接 @Mock 并显式定义行为
推荐做法如下(以 FileService 为被测目标):
@ExtendWith(MockitoExtension.class)
public class FileServiceImplTest {
@Mock
ServiceClass serviceClass; // 模拟一级依赖
@Mock
UtilsClass utilsClass; // 模拟二级依赖
@Spy // 注意:这里用 @Spy,而非 @InjectMocks
FileService fileService; // Spy 会创建真实实例,并将 @Mock/@Spy 字段注入其中
@BeforeEach
void setUp() {
// 确保 serviceClass 中的 utilsClass 被正确注入(Spy 会尝试注入)
ReflectionTestUtils.setField(serviceClass, "utilsClass", utilsClass);
}
@Test
void testMethod_class_FileService() {
// 配置底层行为
when(utilsClass.method()).thenReturn("mocked-result");
// 触发被测方法
fileService.method_class_FileService();
// 验证交互
verify(serviceClass).method_service_class();
verify(utilsClass).method();
}
}⚠️ 关键注意事项:
-
@InjectMocks不适用于“依赖链中存在多层@Mock”的场景,尤其当需调用部分真实逻辑时; -
@Spy更适合此类需求:它创建真实对象,并支持选择性 mock 某些方法,同时能配合ReflectionTestUtils手动注入 mock 依赖; - 若坚持使用
@InjectMocks,必须确保所有中间依赖(如ServiceClass)不被@Mock,而应声明为@Spy或通过构造器注入@Mock实例,否则注入失效; -
thenCallRealMethod()仅对当前 mock 对象生效,不会自动修复其内部未注入的依赖——这是常见误区。
总结:Mockito 的依赖注入是单层、非递归的。面对嵌套依赖结构,优先采用 @Spy + 显式字段注入(ReflectionTestUtils)或重构为构造器注入(便于测试时传入 fully-mocked 依赖),可显著提升测试稳定性与可维护性。

















