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

引入spring-cloud-contract-wiremock后后续带@SqlGroup注解的测试执行失败

问题根因

该问题是Spring测试上下文缓存 + 数据库状态污染共同导致的:

  1. 你原有测试的@SpringBootTest默认使用MOCK类型的web环境,新增的WireMock测试指定了RANDOM_PORT类型的Servlet web环境,两者属于不同的Spring上下文配置,Spring测试框架会分别缓存上下文
  2. 如果WireMock测试运行过程中修改了数据库数据,且没有做数据回滚/上下文清理,后续普通测试复用上下文或者访问同一个数据库时,就会因为已有脏数据导致@Sql脚本执行失败(最常见的是主键冲突、表已存在等报错)

解决方案

你可以按优先级选择以下任意一种方案:

  • 方案1(最通用、改动最小):给WireMock测试类添加@DirtiesContext注解,指定类运行完后直接销毁当前上下文:
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWireMock(port = 10000, stubs = {"classpath:stubs/mappings"})
@ActiveProfiles({"test"})
public class YourWireMockTest {
    // 测试逻辑
}

该方案会强制跑完WireMock测试后销毁对应的Spring上下文,后续的普通测试会重新加载原本的非web环境上下文,同时如果使用的是内存型数据库(如H2),内存数据也会随上下文销毁被清空,彻底避免脏数据影响。

  • 方案2(适合WireMock测试不需要操作数据库的场景):调整@Sql脚本为幂等写法,避免重复执行报错:

    • 插入数据前先判断是否存在,比如MySQL可以用INSERT IGNORE INTO、ON DUPLICATE KEY UPDATE,H2可以用MERGE INTO语法
    • 在@SqlGroup里增加测试前清理数据的脚本,先清空对应表再执行初始化语句
  • 方案3(适合所有测试需要复用同一个上下文的场景):统一所有测试的@SpringBootTest配置,给原有普通测试也加上webEnvironment = SpringBootTest.WebEnvironment.MOCK显式声明,同时给所有需要修改数据库的测试类添加@Transactional注解,测试方法跑完后自动回滚事务(注意:RANDOM_PORT环境下@Transactional默认不生效,因为Servlet线程和测试线程事务不共享,所以该场景还是优先选方案1)


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 16:36:04