Gradle Test Retry搭配Serenity Test:如何统一合并测试结果?
解决Serenity Test与gradle-test-retry插件的结果覆盖问题
问题核心:org.gradle.test-retry插件的重试操作会被Serenity视为独立执行,每次重试都会生成新的serenityTest.json覆盖原有文件,导致最终报告只保留最后一次重试的结果,且默认aggregate任务无法自动合并这些分散的结果。
以下是两种可行的解决思路:
方案一:自定义结果合并任务(推荐)
通过将主执行和每次重试的结果输出到独立目录,再编写自定义任务合并所有结果,确保aggregate能读取到完整的测试数据。
修改build.gradle配置
plugins { id "net.serenity-bdd.serenity-gradle-plugin" version "4.2.34" id 'java' id 'org.gradle.test-retry' version "1.6.2" } tasks.register('e2e-test', Test) { // 原有测试配置(如testClassesDirs、classpath等) gradle.startParameter.setContinueOnFailure(true) // 主执行的结果输出到独立目录 systemProperty 'serenity.outputDirectory', "build/reports/serenity/main" retry { if (System.getenv("GITLAB_CI")) { maxRetries = 3 maxFailures = 10 } failOnPassedAfterRetry = false // 每次重试输出到不同子目录,避免覆盖 onRetry { attempt -> systemProperty 'serenity.outputDirectory', "build/reports/serenity/retry-${attempt}" } } // 先执行合并任务,再执行aggregate finalizedBy(mergeSerenityResults, aggregate) } // 自定义合并任务:合并所有重试目录的测试结果 tasks.register('mergeSerenityResults') { dependsOn('e2e-test') doLast { def baseDir = file("build/reports/serenity") def mainDir = baseDir.dir("main") def retryDirs = baseDir.listFiles().findAll { it.name.startsWith("retry-") && it.isDirectory() } def mergedResults = [] def jsonSlurper = new groovy.json.JsonSlurper() // 读取主执行的结果 def mainJson = mainDir.file("serenityTest.json") if (mainJson.exists()) { mergedResults.addAll(jsonSlurper.parse(mainJson)) } // 读取并合并重试结果:用最新的重试结果覆盖之前失败的测试 retryDirs.each { dir -> def retryJson = dir.file("serenityTest.json") if (retryJson.exists()) { def retryTests = jsonSlurper.parse(retryJson) retryTests.each { retryTest -> def existingIdx = mergedResults.findIndexOf { it.testId == retryTest.testId } if (existingIdx != -1) { mergedResults[existingIdx] = retryTest } else { mergedResults.add(retryTest) } } } } // 将合并后的结果写入aggregate默认读取的目录 def aggregateTargetDir = baseDir aggregateTargetDir.mkdirs() new File(aggregateTargetDir, "serenityTest.json").write( new groovy.json.JsonBuilder(mergedResults).toPrettyString() ) // 复制所有报告资源(截图、HTML片段等)到目标目录 [mainDir, *retryDirs].each { sourceDir -> copy { from sourceDir into aggregateTargetDir include "**/*" exclude "serenityTest.json" } } } }
方案说明
- 主执行和每次重试的结果分别输出到
main和retry-N目录,彻底避免文件覆盖 - 合并任务会将所有重试的测试结果与主执行结果合并,用重试的最新结果覆盖原有失败的测试记录
- 最后将合并后的结果和所有报告资源统一放到
aggregate任务默认读取的目录,确保生成完整报告
方案二:配置aggregate任务读取所有重试目录(简洁版)
如果Serenity的aggregate任务支持通配符路径,可以直接配置其读取所有重试目录的结果,无需自定义合并任务。
修改build.gradle配置
plugins { id "net.serenity-bdd.serenity-gradle-plugin" version "4.2.34" id 'java' id 'org.gradle.test-retry' version "1.6.2" } tasks.register('e2e-test', Test) { // 原有测试配置 gradle.startParameter.setContinueOnFailure(true) systemProperty 'serenity.outputDirectory', "build/reports/serenity/main" retry { if (System.getenv("GITLAB_CI")) { maxRetries = 3 maxFailures = 10 } failOnPassedAfterRetry = false onRetry { attempt -> systemProperty 'serenity.outputDirectory', "build/reports/serenity/retry-${attempt}" } } finalizedBy(aggregate) } // 配置aggregate任务读取所有主执行和重试目录的结果 tasks.named('aggregate') { dependsOn('e2e-test') // 用逗号分隔所有需要聚合的目录,支持通配符(需确认Serenity版本兼容性) systemProperty 'serenity.aggregate.source', 'build/reports/serenity/main,build/reports/serenity/retry-*' }
注意事项
- 部分Serenity版本可能不支持通配符路径,若此方案无效,请切换到方案一
- Serenity的
aggregate任务会自动处理重复的测试用例,保留最新的执行结果
内容的提问来源于stack exchange,提问作者Ragnarsson
相关产品推荐
相关产品推荐

