如何在Mongock集成测试中执行指定范围的change-units
如何在集成测试中执行特定范围的Change Units?
场景说明
现有三个Change Unit:X、Y、Z(order分别设为1、2、3),对应集成测试T1(需仅执行X、Y的迁移)和T2(需仅执行Z的迁移),需要在T1中跳过Z的迁移。
现有方案及不足
你提到的两种方案存在明显弊端:
- 方案1:将迁移文件按组放入不同包,通过
runnerBuilder.addMigrationScanPackage指定扫描包。不足:需要为迁移单独创建包结构,增加不必要的代码分层复杂度。 - 方案2:使用
ChangeUnit#systemVersion,通过setStartSystemVersion和setEndSystemVersion限定范围。不足:SystemVersion设计初衷并非用于测试分组,且需要同步order与systemVersion,维护成本高,容易出错。
替代解决方案
1. 自定义注解+ChangeUnit过滤器
通过给Change Unit添加自定义分组注解,再在测试中通过过滤器筛选目标分组的迁移单元,语义清晰且无额外结构成本。
步骤如下:
- 定义自定义分组注解:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestMigrationGroup { String value(); // 分组标识,比如"t1"、"t2" } - 给目标Change Unit标记注解:
@TestMigrationGroup("t1") @ChangeUnit(order = 1, id = "X") public class MigrationX { /* 迁移逻辑 */ } @TestMigrationGroup("t1") @ChangeUnit(order = 2, id = "Y") public class MigrationY { /* 迁移逻辑 */ } @TestMigrationGroup("t2") @ChangeUnit(order = 3, id = "Z") public class MigrationZ { /* 迁移逻辑 */ } - 在T1测试中配置过滤器,仅执行
t1分组的迁移:@Test void executeT1Migrations() { MigrationRunner runner = MigrationRunnerBuilder.builder() .addMigrationScanPackage("com.your.migration.package") .changeUnitFilter(changeUnit -> { TestMigrationGroup groupAnnotation = changeUnit.getMigrationClass() .getAnnotation(TestMigrationGroup.class); return groupAnnotation != null && "t1".equals(groupAnnotation.value()); }) .build(); runner.execute(); }
2. 环境变量/配置驱动的ID筛选
通过外部环境变量或测试配置指定要执行的Change Unit ID,灵活性极高,适合CI/CD场景下动态切换测试范围。
示例实现:
@Test void executeT1Migrations() { // 从环境变量读取要包含的Change Unit ID,也可从测试配置文件读取 String includedIds = System.getenv("INCLUDE_CHANGE_UNITS"); Set<String> targetIds = new HashSet<>(Arrays.asList(includedIds.split(","))); MigrationRunner runner = MigrationRunnerBuilder.builder() .addMigrationScanPackage("com.your.migration.package") .changeUnitFilter(changeUnit -> targetIds.contains(changeUnit.getId())) .build(); runner.execute(); }
运行T1测试时,只需设置环境变量INCLUDE_CHANGE_UNITS=X,Y即可;运行T2时设置为INCLUDE_CHANGE_UNITS=Z。
3. 基于Order范围的筛选(适合按顺序分组场景)
如果你的Change Unit已经按order有序排列,可直接在测试中通过过滤器限定order的范围,无需额外注解或配置:
@Test void executeT1Migrations() { MigrationRunner runner = MigrationRunnerBuilder.builder() .addMigrationScanPackage("com.your.migration.package") .changeUnitFilter(changeUnit -> { int order = changeUnit.getOrder(); return order >= 1 && order <= 2; // 仅执行order为1、2的X、Y }) .build(); runner.execute(); }
如果是Spring环境,还可以通过@TestPropertySource将范围参数化,进一步提升灵活性:
@TestPropertySource(properties = {"migration.start.order=1", "migration.end.order=2"}) public class T1IntegrationTest { @Autowired private Environment env; @Test void runMigrations() { int startOrder = Integer.parseInt(env.getProperty("migration.start.order")); int endOrder = Integer.parseInt(env.getProperty("migration.end.order")); MigrationRunner runner = MigrationRunnerBuilder.builder() .addMigrationScanPackage("com.your.migration.package") .changeUnitFilter(changeUnit -> changeUnit.getOrder() >= startOrder && changeUnit.getOrder() <= endOrder) .build(); runner.execute(); } }
方案对比
| 方案 | 优势 | 适用场景 |
|---|---|---|
| 自定义注解筛选 | 语义清晰,代码耦合低 | 固定分组的测试场景 |
| 环境变量/配置驱动 | 灵活性高,支持动态切换 | CI/CD流水线、多环境测试 |
| Order范围筛选 | 无需额外代码,利用现有属性 | Change Unit按顺序明确分组的场景 |
内容的提问来源于stack exchange,提问作者Filip Kowalski
相关产品推荐
相关产品推荐

