如何实现多层Mock对象注入?解决UserSshKeyService空指针异常
多层依赖的Mock注入问题解决方法
场景代码
UserSshKeyService实现
@Service public class UserSshKeyService { private final RecordEventService eventService; private final UserSshKeyRepository repository; public UserSshKeyService(RecordEventService eventService, UserSshKeyRepository repository){} }
RecordEventService实现
@Service public class RecordEventService { private final UserSshKeyEventLogRepository repository; // 注意:原始代码此处构造方法类名写错,需修正为RecordEventService public RecordEventService(UserSshKeyEventLogRepository repository){} }
尝试的测试写法
写法一
@InjectMocks private UserSshKeyService userSshKeyService; @InjectMocks private RecordEventService eventService; @Mock UserSshKeyRepository userSshKeyRepository; @Mock UserSshKeyEventLogRepository userSshKeyEventLogRepository;
写法二
@InjectMocks private UserSshKeyService userSshKeyService; @Spy @InjectMocks private RecordEventService eventService; @Mock UserSshKeyRepository userSshKeyRepository; @Mock UserSshKeyEventLogRepository userSshKeyEventLogRepository;
遇到的问题
执行测试时,UserSshKeyService中的eventService抛出空指针异常,无法完成多层对象的Mock注入。
解决方法
核心问题说明
@InjectMocks的逻辑很明确:只把测试类中标记为@Mock/@Spy的对象,注入到被@InjectMocks标记的目标对象里。你之前的写法里,userSshKeyService和eventService都是被注入的目标,Mockito不会把一个注入目标当成另一个的依赖源,所以userSshKeyService里的eventService自然是空的。
正确实现方式
方案一:用@Mock完全模拟RecordEventService
如果不需要RecordEventService的真实逻辑,直接把它标记为@Mock,让Mockito自动注入到上层的UserSshKeyService中:
// 测试类需加注解:JUnit4用@RunWith(MockitoJUnitRunner.class),JUnit5用@ExtendWith(MockitoExtension.class) @InjectMocks private UserSshKeyService userSshKeyService; @Mock private RecordEventService eventService; @Mock private UserSshKeyRepository userSshKeyRepository; @Mock private UserSshKeyEventLogRepository userSshKeyEventLogRepository;
方案二:用@Spy保留RecordEventService的真实逻辑
如果需要RecordEventService执行真实代码,就用@Spy标记,同时确保它的依赖被正确注入:
@InjectMocks private UserSshKeyService userSshKeyService; @Spy private RecordEventService eventService; @Mock private UserSshKeyRepository userSshKeyRepository; @Mock private UserSshKeyEventLogRepository userSshKeyEventLogRepository; @Before public void setUp() { // 初始化Mockito注解,确保依赖注入生效 MockitoAnnotations.openMocks(this); // 也可以手动构造Spy对象,避免依赖自动注入可能的问题 // eventService = new RecordEventService(userSshKeyEventLogRepository); }
额外注意事项
- 修正
RecordEventService的构造方法:原始代码里构造方法的类名写错成了UserSshKeyService,这个错误会导致Mockito无法正常实例化对象,也是空指针的潜在诱因。 - 必须给测试类添加Mockito的运行器/扩展注解,否则
@Mock、@InjectMocks等注解不会生效。
内容的提问来源于stack exchange,提问作者seunggyu lee
相关产品推荐
相关产品推荐

