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___
相关产品推荐
相关产品推荐

