如何为多模块项目创建聚合Jacoco测试覆盖率报告?
多模块Android项目Jacoco合并报告+SonarCloud提交方案
适配环境
完全匹配你使用的版本组合:
- Gradle version: 7.0.2
- Kotlin version: 1.5.21
- JDK: 11
配置步骤
1. 子模块统一Jacoco配置
在项目根目录新建jacoco.gradle文件,所有需要统计覆盖率的Android子模块都引入该配置:
apply plugin: 'jacoco' jacoco { // Gradle7.0.2适配最优Jacoco版本,不要升级更高版本避免兼容问题 toolVersion = "0.8.7" } android { buildTypes { debug { // 开启覆盖率统计开关 testCoverageEnabled true } } } tasks.withType(Test) { jacoco.includeNoLocationClasses = true jacoco.excludes = ['jdk.internal.*'] } // 子模块单独的Jacoco报告生成任务 task jacocoSubReport(type: JacocoReport) { dependsOn 'testDebugUnitTest' group = "Reporting" description = "Generate Jacoco coverage report for current submodule" // 过滤不需要统计的类 def fileFilter = [ '**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*', '**/databinding/*', '**/BR.*' ] def debugClassTree = fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug", excludes: fileFilter) def javaSrcPath = "${project.projectDir}/src/main/java" def kotlinSrcPath = "${project.projectDir}/src/main/kotlin" sourceDirectories.setFrom files([javaSrcPath, kotlinSrcPath]) classDirectories.setFrom files([debugClassTree]) // 同时支持单元测试和instrumented测试的覆盖率数据 executionData.setFrom fileTree(dir: buildDir, includes: [ "jacoco/testDebugUnitTest.exec", "outputs/code_coverage/debugAndroidTest/connected/*.ec" ]) reports { xml.enabled = true html.enabled = true } }
在每个需要统计的子模块build.gradle顶部添加引入:
apply from: rootProject.file('jacoco.gradle')
2. 根目录聚合报告配置
在根项目的build.gradle中添加聚合任务:
apply plugin: 'jacoco' apply plugin: 'org.sonarqube' // 聚合所有子模块的Jacoco报告 task jacocoAggregateReport(type: JacocoReport) { group = "Reporting" description = "Aggregate Jacoco coverage reports from all submodules" // 可在这里过滤不需要统计覆盖率的子模块 def includedSubprojects = subprojects.findAll { it.name != "不需要统计的模块名" } dependsOn includedSubprojects.jacocoSubReport sourceDirectories.setFrom files(includedSubprojects.jacocoSubReport.sourceDirectories) classDirectories.setFrom files(includedSubprojects.jacocoSubReport.classDirectories) executionData.setFrom files(includedSubprojects.jacocoSubReport.executionData) reports { xml { enabled = true destination = file("${buildDir}/reports/jacoco/aggregate.xml") } html { enabled = true destination = file("${buildDir}/reports/jacoco/html") } } doFirst { // 过滤不存在的执行数据文件避免报错 executionData.setFrom files(executionData.findAll { it.exists() }) } } // SonarCloud配置,也可以写在单独的sonar-project.properties文件中 sonarqube { properties { property "sonar.host.url", "https://sonarcloud.io" property "sonar.organization", "你的SonarCloud组织ID" property "sonar.projectKey", "你的项目唯一Key" property "sonar.java.coveragePlugin", "jacoco" property "sonar.coverage.jacoco.xmlReportPaths", "${buildDir}/reports/jacoco/aggregate.xml" property "sonar.exclusions", "**/R.class,**/R$*.class,**/BuildConfig.*,**/*Test*.*" } }
3. 执行命令
# 生成全模块聚合覆盖率报告 ./gradlew jacocoAggregateReport # 提交报告到SonarCloud ./gradlew sonarqube
常见问题修复
- 类路径匹配错误:如果出现覆盖率为0的情况,检查子模块
jacocoSubReport中的类输出路径是否和你的项目构建输出路径一致,部分AGP版本的Kotlin类输出路径可能为intermediates/javac/debug - 任务依赖缺失:确保执行sonarqube任务前已经成功生成了聚合的xml报告
内容的提问来源于stack exchange,提问作者nuhkoca
相关产品推荐
相关产品推荐

