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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 09:32:45