You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Mockito创建的Mock对象中注入Spring Boot真实Bean?

解决Mock UserService时注入真实UserRepository的问题

这是个很典型的Mockito使用误区——你混淆了完全Mock和**部分Mock(Spy)**的场景,我来帮你理清思路并解决问题:

问题本质

你用@Mock创建的UserService是一个完全模拟的假对象,所有方法默认都是空实现,Spring不会把真实的UserRepository注入进去(因为mock对象根本不是Spring容器管理的Bean)。而@InjectMocks只会把其他@Mock标记的对象注入进去,不会自动关联真实的Bean,这就是为什么你会遇到空指针异常。

正确方案:使用Mockito Spy(部分Mock)

你真正需要的是保留UserService的真实行为,仅跳过validateUser和createToken这两个方法,这时候应该用Mockito的Spy来包装真实的UserService实例——Spy会基于真实对象创建代理,既保留原对象的依赖(已经被Spring注入好的UserRepository),又允许你mock特定方法。

实现方式1:手动创建Spy(基础写法)

@SpringBootTest
public class UserServiceTest {

    // 让Spring注入真实的UserService(里面已经包含真实的UserRepository)
    @Autowired
    private UserService realUserService;

    @Test
    public void testUpdateUser() {
        // 基于真实对象创建Spy
        UserService spyUserService = Mockito.spy(realUserService);

        // 跳过validateUser和createToken方法
        Mockito.doNothing().when(spyUserService).validateUser(Mockito.any());
        Mockito.doNothing().when(spyUserService).createToken(Mockito.any());

        // 调用spy对象的updateUser,此时内部的UserRepository是真实的
        spyUserService.updateUser(yourUserParam);

        // 后续断言逻辑
    }
}

实现方式2:用Spring Boot的@SpyBean注解(更简洁)

Spring Boot提供了@SpyBean注解,可以直接把Spring容器里的真实Bean包装成Spy,不需要手动创建:

@SpringBootTest
public class UserServiceTest {

    // 自动把容器里的真实UserService包装成Spy
    @SpyBean
    private UserService userService;

    @Autowired
    private UserRepository userRepository; // 可选,如果你需要直接操作Repository做断言

    @Test
    public void testUpdateUser() {
        // 跳过指定方法
        Mockito.doNothing().when(userService).validateUser(Mockito.any());
        Mockito.doNothing().when(userService).createToken(Mockito.any());

        // 调用updateUser,内部UserRepository是真实的
        userService.updateUser(yourUserParam);

        // 比如断言Repository里的数据是否正确更新
        User updatedUser = userRepository.findById(yourUserId).orElseThrow();
        Assertions.assertEquals(yourExpectedValue, updatedUser.getSomeField());
    }
}

关键注意事项

  • 不要把@Mock和@SpyBean混用在同一个类上,避免依赖混乱
  • 如果你只需要测试Service层和Repository的交互,也可以用@DataJpaTest配合@Import(UserService.class)来缩小上下文范围,提升测试速度
  • 用doNothing()的时候,要注意方法的返回值:如果validateUser或createToken有返回值,可能需要用doReturn()代替,比如doReturn(true).when(spyUserService).validateUser(Mockito.any())

内容的提问来源于stack exchange,提问作者pizza.addict

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:30:27