Android应用Jacoco代码覆盖率报告显示0%但测试报告数据正常
Jacoco覆盖率报告0%问题排查与解决
问题背景
此前使用Jacoco生成代码覆盖率报告正常,项目基于JUnit5编写单元测试,依赖de.mannodermaus.android插件支持JUnit5。更新相关依赖后出现异常:
- 执行Jacoco Gradle任务后,覆盖率报告显示0%
- 测试结果报告正常,可正确展示测试成功/失败状态
已确认Java与Kotlin类文件路径无误,当前环境:Gradle插件7.2.2、Gradle distribution 7.3.3。
相关配置
应用级Build.gradle
apply from: '../jacoco-config.gradle' apply plugin: "de.mannodermaus.android-junit5" androidTestImplementation "de.mannodermaus.junit5:android-test-core:1.3.0" androidTestRuntimeOnly "de.mannodermaus.junit5:android-test-runner:1.3.0" // (Required) Writing and executing Unit Tests on the JUnit Platform testImplementation "org.junit.jupiter:junit-jupiter-api:5.8.2" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.8.2" // (Optional) If you need "Parameterized Tests" testImplementation "org.junit.jupiter:junit-jupiter-params:5.8.2" // (Optional) If you also have JUnit 4-based tests testRuntimeOnly "org.junit.vintage:junit-vintage-engine:5.8.2" testImplementation "junit:junit:4.13.2"
项目级Build.gradle
classpath "org.jacoco:org.jacoco.core:0.8.8" classpath "de.mannodermaus.gradle.plugins:android-junit5:1.8.2.1"
jacoco-config.gradle核心配置
apply plugin: 'jacoco' tasks.withType(Test) { jacoco.includeNoLocationClasses = true jacoco.excludes = ['jdk.internal.*']} jacoco { toolVersion = "0.8.8" reportsDir = file("$buildDir/JacocoReport")} android { buildTypes { debug { testCoverageEnabled = true } } testOptions { animationsDisabled true unitTests { includeAndroidResources = true returnDefaultValues = true } } } project.afterEvaluate { project.gradle.taskGraph.whenReady { testDebugUnitTest { ignoreFailures true } } def androidExclusion = [ '**/BR.*', '**/R.*', '**/R$*.*', '**/BuildConfig.*', '**/Manifest*.*', '**/databinding/*.*' ] // Create coverage task ex: 'jacocoTestReport<Flavor>' depending on task "jacocoTestReport"(type: JacocoReport, dependsOn: ['testDebugUnitTest']) { group = "Reporting" description = "Generate Jacoco coverage reports on the testDebugUnitTest build." def javaClasses = fileTree( dir: "${project.buildDir}/intermediates/javac/debug", excludes: androidExclusion) def kotlinClasses = fileTree( dir: "${project.buildDir}/tmp/kotlin-classes/debug", excludes: androidExclusion) classDirectories.from = files([ kotlinClasses , javaClasses]) def coverageSourceDirs = ["src/main/java"] getAdditionalSourceDirs().setFrom(files(coverageSourceDirs)) getSourceDirectories().setFrom(files(coverageSourceDirs)) getExecutionData().setFrom(fileTree(dir: project.projectDir, includes: ["**/*.exec", "**/*.ec"])) reports { xml.required = true html.required = true } } }
解决步骤
1. 修正Jacoco执行数据路径
Gradle 7.x+中,JUnit5测试的Jacoco执行数据默认生成在build/outputs/unit_test_code_coverage/debugUnitTest或build/jacoco目录下,而非项目根目录。修改jacocoTestReport中的executionData配置:
getExecutionData().setFrom(fileTree(dir: "${project.buildDir}", includes: [ "outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec", "jacoco/testDebugUnitTest.exec" ]))
2. 适配AGP 7.x的类文件路径
Android Gradle Plugin 7.x调整了编译后类文件的存放路径:
- Java类文件从
intermediates/javac/debug改为intermediates/javac/debug/classes - Kotlin类文件从
tmp/kotlin-classes/debug改为intermediates/kotlin/debug/classes
更新类文件路径配置:
def javaClasses = fileTree( dir: "${project.buildDir}/intermediates/javac/debug/classes", excludes: androidExclusion) def kotlinClasses = fileTree( dir: "${project.buildDir}/intermediates/kotlin/debug/classes", excludes: androidExclusion)
3. 升级Jacoco版本以适配新AGP
当前使用的Jacoco 0.8.8对AGP 7.x的兼容性有限,建议升级到0.8.10:
- 项目级Build.gradle:
classpath "org.jacoco:org.jacoco.core:0.8.10"
- jacoco-config.gradle:
jacoco { toolVersion = "0.8.10" }
4. 清理冗余依赖避免冲突
同时引入JUnit4和JUnit5依赖可能导致测试执行逻辑冲突,若项目无JUnit4测试,移除相关依赖:
// 移除这两行 // testImplementation "junit:junit:4.13.2" // testRuntimeOnly "org.junit.vintage:junit-vintage-engine:5.8.2"
5. 强制启用Jacoco测试数据生成
在tasks.withType(Test)中明确启用Jacoco,确保测试任务生成执行数据:
tasks.withType(Test) { jacoco.includeNoLocationClasses = true jacoco.excludes = ['jdk.internal.*'] jacoco.enabled = true // 新增此行 }
完成以上修改后,重新执行jacocoTestReport任务,即可正常生成覆盖率报告。
内容的提问来源于stack exchange,提问作者Orton
相关产品推荐
相关产品推荐

