Gradle多模块中根项目执行./gradlew test会依次触发各子项目test任务(如A:test、B:test),任务彼此隔离;要汇总测试结果,需显式定义TestReport聚合任务并禁用子项目JUnit XML报告。

根项目中执行子模块任务的默认行为
在 Gradle 多模块项目中,./gradlew test 或 ./gradlew build 在根目录执行时,并不是“汇总”任务,而是**依次触发每个子项目中同名任务**(如 A:test、B:test、C:test)。这看起来像汇总,实则是串行调用,各子项目任务彼此隔离,输出、失败、配置互不影响。
如何让根项目真正“汇总”测试结果
Gradle 本身不提供开箱即用的“合并测试报告”能力。你需要显式定义一个聚合任务,把各子项目 test 的输出作为输入源:
-
testReport是标准方式:它不运行测试,只读取已生成的junitXml结果并合并成 HTML 报告 - 必须先禁用各子项目的独立报告(避免干扰路径和资源竞争):
test.reports.junitXml.enabled = false - 聚合任务需声明
reportOn subprojects*.test,且确保所有子项目都已应用java插件
示例(根项目 build.gradle):
task testReport(type: TestReport) {
destinationDir = file("$buildDir/reports/allTests")
reportOn subprojects*.test
}
执行 ./gradlew testReport 前,需先运行 ./gradlew test —— 否则 testReport 找不到 XML 文件。
为什么 ./gradlew :A:build 不触发依赖模块的 build
Gradle 默认不会递归构建被依赖的子模块,哪怕 A 通过 implementation project(':B') 引用了 B。原因在于:build 是生命周期任务,不参与依赖解析;只有编译、测试等实际需要输出的任务(如 classes、testClasses)才受依赖关系驱动。
- 想强制构建依赖链,得显式调用:
./gradlew :A:build :B:build - 或在
A/build.gradle中添加:tasks.named('compileJava').configure { dependsOn ':B:classes' } - 更稳妥的做法是:对关键产出(如 JAR)建模为
Artifact,再用from+project().tasks显式拉取
汇总 Jacoco 覆盖率报告的关键限制
jacocoTestReport 默认只生成各子模块独立报告。要汇总到根目录 HTML,必须启用 jacocoRootReport 并确保:
- 所有子项目都应用了
jacoco插件(不能只在根项目 apply) - 各子项目的
test任务已执行(生成jacoco.exec) - 根项目中定义的汇总任务使用
executionData指向全部子模块的build/jacoco/test.exec
容易忽略的一点:jacocoRootReport 不会自动发现子项目——你得手动写 subprojects*.tasks.jacocoTestReport 或用 fileTree 收集,否则报告为空。











