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

Spring Boot测试问题:Mock仓库无法保存数据致查询失败

问题根源

你这测试代码的核心问题是混用了Mockito模拟对象和Spring Boot集成测试:

  • @Mock注解创建的是一个空实现的模拟UserRepository,调用它的save()方法根本不会把数据存到H2数据库里,只是个空调用
  • 你没给模拟的searchByUserName()方法设置返回值,所以默认会返回Optional.empty(),直接触发UserService里的UsernameNotFoundException
两种解决方案

根据你想要的测试类型,选下面其中一种:

方案一:纯单元测试(只测UserService逻辑)

不需要启动Spring上下文,只用Mockito模拟Repository,给它设置预期行为就行:

@ExtendWith(MockitoExtension.class)
class AppUserServiceTest {

    @Mock
    private UserRepository repository;
    private UserService userService;

    @BeforeEach
    void setUp() {
        userService = new UserService(repository);
    }

    @Test
    void itShouldLoadUsernameByName() {
        // 准备测试用户
        AppUser appUser = new AppUser(
                ApplicationRole.USER,
                "leonardo",
                "rossi",
                "leo__",
                "a@gmail.com",
                "password"
        );

        // 告诉Mock:当调用searchByUserName传入这个用户名时,返回我们准备好的用户
        when(repository.searchByUserName(appUser.getUsername()))
                .thenReturn(Optional.of(appUser));

        // 执行测试方法
        UserDetails result = userService.loadUserByUsername(appUser.getUsername());

        // 验证结果正确,并且确实调用了searchByUserName方法
        assertNotNull(result);
        assertEquals(appUser.getUsername(), result.getUsername());
        verify(repository).searchByUserName(appUser.getUsername());
    }
}

方案二:集成测试(测Service+Repository+数据库的完整链路)

如果要验证真实的数据库操作,就用Spring注入真实的Repository,加上@Transactional保证测试后数据自动回滚:

@SpringBootTest
@Transactional // 测试完自动删数据,不影响其他测试
class AppUserServiceTest {

    @Autowired
    private UserRepository repository;
    @Autowired
    private UserService userService;

    @Test
    void itShouldLoadUsernameByName() {
        // 把用户存到真实的H2数据库里
        AppUser appUser = new AppUser(
                ApplicationRole.USER,
                "leonardo",
                "rossi",
                "leo__",
                "a@gmail.com",
                "password"
        );
        repository.save(appUser);

        // 调用Service方法
        UserDetails result = userService.loadUserByUsername(appUser.getUsername());

        // 验证能正确查到用户
        assertNotNull(result);
        assertEquals(appUser.getUsername(), result.getUsername());
    }
}
注意事项
  • 单元测试速度快,只聚焦Service的逻辑,用Mock隔离外部依赖
  • 集成测试要启动Spring上下文,验证完整流程,适合测试数据库交互这类场景
  • 别再把@Mock和@SpringBootTest混着用了,不然注入的是模拟对象,根本连不上H2数据库

内容的提问来源于stack exchange,提问作者leo___

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 20:35:22