You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为多模块项目创建聚合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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 15:54:06