使用SpringBootTest测试时H2数据库无法保存数据求助
解决SpringBootTest中H2数据库不保存数据且无INSERT语句的问题
我来帮你排查下问题根源,你遇到的情况主要由两个关键问题导致:
1. Mock对象导致数据库操作被“模拟”而非真实执行
你在测试类里用@Mock注解了CustDetailsRepository和BCryptPasswordEncoder,这意味着这两个对象是模拟的假对象,不会执行真实的业务逻辑:
- 调用
custDetailsRepository.save()时,Mock对象只会空执行,不会真的向H2数据库发送INSERT语句 - 同样,Mock的
BCryptPasswordEncoder也不会真正加密密码,只是返回一个模拟值
2. @Transactional注解的事务回滚(次要原因)
你的测试类加了@Transactional,Spring Boot Test默认会在测试结束后自动回滚事务。不过这一步的前提是真实执行了数据库操作——但因为第一个问题,你连INSERT都没触发,所以这不是当前的核心问题。
解决步骤及修改后的代码
第一步:替换Mock对象为真实Bean
要测试真实的数据库操作,需要注入Spring容器中真实的Repository、密码编码器和Service,而不是Mock它们:
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) @ContextConfiguration(classes=ConnectionsAppApplication.class) @Transactional public class AuthenticationTest { @Autowired private WebApplicationContext context; private MockMvc mockMvc; // 替换@Mock为@Autowired,注入容器中的真实Bean @Autowired private CustDetailsRepository custRepository; @Autowired private BCryptPasswordEncoder encrypt; @Autowired private CustomerServiceImpl customerServiceImpl; @BeforeEach public void setup() { // 无需再初始化Mock,直接使用Autowired注入的真实Bean mockMvc = MockMvcBuilders .webAppContextSetup(context) .apply(springSecurity()) .build(); } @Test void testAuthentication() { CustomerDetails customer = new CustomerDetails(); // 注意:原邮箱格式错误,改为合法格式避免认证失败 customer.setEmailid("abc@example.com"); customer.setPassword("abc@123456"); customerServiceImpl.saveUser(customer); try { this.mockMvc.perform(get("/api/login") .with(httpBasic("abc@example.com","abc@123456"))) .andDo(print()) .andExpect(status().isOk()) .andReturn(); } catch (Exception e) { e.printStackTrace(); } } }
第二步:可选:禁用事务回滚(如果需要测试后保留数据)
如果你希望测试结束后数据保留在H2中,可以给测试方法或类加上@Rollback(false)注解:
@Rollback(false) @Test void testAuthentication() { // ... 测试代码 ... }
为什么这样修改有效?
- 注入真实的
CustDetailsRepository后,调用save()会触发真实的JPA操作,控制台会清晰打印出INSERT语句 - 即使保留
@Transactional,控制台也会先打印INSERT,测试结束后打印ROLLBACK语句(未加@Rollback(false)时) - 修正了邮箱格式错误,避免因邮箱不合法导致的认证失败问题
内容的提问来源于stack exchange,提问作者Shridha Jalihal
相关产品推荐
相关产品推荐

