如何用Gradle实现部分Cucumber测试并行、其余串行执行?
解决方案:Gradle中混合并行/串行执行Cucumber测试
一、当前实现的问题分析
你的核心思路(先跑并行测试,再跑串行测试)是可行的,但当前代码存在两个关键问题:
- 不必要的
exec嵌套:第二次Cucumber执行被包裹在exec块中,这会触发Gradle额外启动进程,大概率是导致2分钟延迟的原因。 - 标签逻辑丢失:第二次执行硬编码了标签
(@api) and (not @parallel),没有保留用户传入的原始过滤条件(比如not @skip、not @bug)。
二、修正后的基础实现
直接在doLast中连续调用两次javaexec,去掉多余的exec嵌套,同时修正标签逻辑,完整保留原始过滤条件:
task("cucumber") { dependsOn("assemble", "compileTestJava") doLast { val baseTags = getProperty("tags", "((@api) and (not @skip) and (not @bug))") // 1. 运行带@parallel标签的测试(并行) val parallelTags = "$baseTags and @parallel" javaexec { mainClass.set("io.cucumber.core.cli.Main") classpath = cucumberRuntime + sourceSets.main.get().output + sourceSets.test.get().output systemProperties(System.getProperties().mapKeys { it.key as String }) args = listOf( "--plugin", "io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm", "--glue", "com.myproject", "src/test/resources", "--tags", parallelTags, "--threads", "4" ) environment("tags", parallelTags) } // 2. 运行不带@parallel标签的测试(串行) val serialTags = "$baseTags and not @parallel" javaexec { mainClass.set("io.cucumber.core.cli.Main") classpath = cucumberRuntime + sourceSets.main.get().output + sourceSets.test.get().output systemProperties(System.getProperties().mapKeys { it.key as String }) args = listOf( "--plugin", "io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm", "--glue", "com.myproject", "src/test/resources", "--tags", serialTags, "--threads", "1" ) environment("tags", serialTags) } } }
这个版本消除了冗余进程开销,应该能解决延迟问题,同时确保所有原始标签过滤条件都被应用。
三、更优的Gradle任务设计
如果追求代码可维护性和调试便利性,建议拆分两个独立任务,再用总任务串联:
// 并行测试任务 task("cucumberParallel") { dependsOn("assemble", "compileTestJava") doLast { val baseTags = getProperty("tags", "((@api) and (not @skip) and (not @bug))") val parallelTags = "$baseTags and @parallel" javaexec { mainClass.set("io.cucumber.core.cli.Main") classpath = cucumberRuntime + sourceSets.main.get().output + sourceSets.test.get().output systemProperties(System.getProperties().mapKeys { it.key as String }) args = listOf( "--plugin", "io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm", "--glue", "com.myproject", "src/test/resources", "--tags", parallelTags, "--threads", "4" ) environment("tags", parallelTags) } } } // 串行测试任务 task("cucumberSerial") { dependsOn("assemble", "compileTestJava") doLast { val baseTags = getProperty("tags", "((@api) and (not @skip) and (not @bug))") val serialTags = "$baseTags and not @parallel" javaexec { mainClass.set("io.cucumber.core.cli.Main") classpath = cucumberRuntime + sourceSets.main.get().output + sourceSets.test.get().output systemProperties(System.getProperties().mapKeys { it.key as String }) args = listOf( "--plugin", "io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm", "--glue", "com.myproject", "src/test/resources", "--tags", serialTags, "--threads", "1" ) environment("tags", serialTags) } } } // 总任务:先跑并行,再跑串行 task("cucumber") { dependsOn("cucumberParallel", "cucumberSerial") // 强制串行任务在并行任务完成后执行 tasks.cucumberSerial.mustRunAfter(tasks.cucumberParallel) }
这种设计的优势:
- 任务职责单一,可单独调试某一类测试(比如
./gradlew cucumberSerial) - 依赖关系明确,执行顺序可控
- 代码复用性强,后续修改只需调整对应任务
四、测试报告合并说明
你使用的Allure报告会自动合并多次执行的结果:两次Cucumber运行的结果默认写入build/allure-results目录,生成最终报告时Allure会自动扫描并合并所有结果文件。如果需要区分并行/串行结果,可自定义输出路径:
// 并行任务指定结果目录 "--plugin", "io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm:build/allure-results/parallel", // 串行任务指定结果目录 "--plugin", "io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm:build/allure-results/serial",
Allure生成报告时会自动识别所有子目录的结果文件。
内容的提问来源于stack exchange,提问作者Aimee Jones
相关产品推荐
相关产品推荐

