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

Android库模块Jacoco失效,coverage.ec文件始终为空

问题

我在类似NowInAndroid的多模块Android项目中配置Jacoco,所用的Jacoco.kt、AndroidApplicationJacocoConventionPlugin和AndroidLibraryJacocoConventionPlugin配置均与NowInAndroid项目一致。运行app模块的androidTest时,coverage.ec文件能正常生成;但运行库模块的androidTest时,生成的coverage.ec文件为空,求解决办法。

配置代码如下:

private val coverageExclusions = listOf(
    // Android
    "**/R.class",
    "**/R\$*.class",
    "**/BuildConfig.*",
    "**/Manifest*.*",
    "**/*_Hilt*.class",
    "**/Hilt_*.class",
)

private fun String.capitalize() = replaceFirstChar {
    if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
}

internal fun Project.configureJacoco(
    androidComponentsExtension: AndroidComponentsExtension<*, *, *>
) {

    configure<JacocoPluginExtension> {
        toolVersion = "0.8.7"
    }

    androidComponentsExtension.onVariants { variant ->
        val myObjFactory = project.objects
        val buildDir = layout.buildDirectory.get().asFile
        val allJars: ListProperty<RegularFile> = myObjFactory.listProperty(RegularFile::class.java)
        val allDirectories: ListProperty<Directory> = myObjFactory.listProperty(Directory::class.java)
        val reportTask =
            tasks.register("create${variant.name.capitalize()}CombinedCoverageReport", JacocoReport::class) {
                classDirectories.setFrom(
                    allJars,
                    allDirectories.map { dirs ->
                        dirs.map { dir ->
                            myObjFactory.fileTree().setDir(dir).exclude(coverageExclusions)
                        }
                    }
                )
                reports {
                    xml.required.set(true)
                    html.required.set(true)
                }

                // TODO: This is missing files in src/debug/, src/prod, src/demo, src/demoDebug...
                sourceDirectories.setFrom(files("$projectDir/src/main"))
                println("This is the projectDir -> ${projectDir}")

                executionData.setFrom(
                    project.fileTree("$buildDir/outputs/unit_test_code_coverage/${variant.name}UnitTest")
                        .matching { include("**/*.exec") },

                    project.fileTree("$buildDir/outputs/code_coverage/${variant.name}AndroidTest")
                        .matching { include("**/*.ec") }
                )
            }


        variant.artifacts.forScope(ScopedArtifacts.Scope.PROJECT)
            .use(reportTask)
            .toGet(
                ScopedArtifact.CLASSES,
                { _ ->
                    allJars },
                { _ ->
                    allDirectories },
            )
    }

    tasks.withType<Test>().configureEach {
        configure<JacocoTaskExtension> {
            // Required for JaCoCo + Robolectric
            // https://github.com/robolectric/robolectric/issues/2230
            isIncludeNoLocationClasses = true

            // Required for JDK 11 with the above
            // https://github.com/gradle/gradle/issues/5184#issuecomment-391982009
            excludes = listOf("jdk.internal.*")
        }
    }

}
解决方案
  • 开启库模块的AndroidTest覆盖率收集
    库模块默认可能未启用AndroidTest代码覆盖率,需在库模块的build.gradle.kts中显式配置:

    android {
        buildTypes {
            named("debug") {
                enableAndroidTestCoverage = true
            }
        }
    }
    
  • 修正覆盖率文件路径匹配规则
    库模块的coverage.ec文件可能存储在子目录中,调整executionData的匹配范围,确保能找到文件:

    executionData.setFrom(
        project.fileTree("$buildDir/outputs/unit_test_code_coverage/${variant.name}UnitTest")
            .matching { include("**/*.exec") },
        project.fileTree("$buildDir/outputs/code_coverage/${variant.name}AndroidTest")
            .matching { include("**/**coverage.ec") } // 匹配所有子目录下的.ec文件
    )
    
  • 确认库模块的Jacoco插件配置生效
    检查库模块的ConventionPlugin是否正确应用Jacoco插件并调用配置方法:

    class AndroidLibraryJacocoConventionPlugin : Plugin<Project> {
        override fun apply(target: Project) {
            with(target) {
                pluginManager.apply("jacoco")
                val androidComponents = extensions.getByType(AndroidComponentsExtension::class.java)
                configureJacoco(androidComponents)
            }
        }
    }
    
  • 升级Jacoco版本
    当前使用的0.8.7版本较旧,可能与新版AGP存在兼容性问题,尝试升级到稳定新版本:

    configure<JacocoPluginExtension> {
        toolVersion = "0.8.12"
    }
    
  • 验证测试用例是否实际执行
    运行库模块AndroidTest任务时,确认测试用例已正常执行——若测试未运行,自然不会生成有效覆盖率数据,可通过测试日志或添加打印语句验证。

内容的提问来源于stack exchange,提问作者Júnio Farias

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:33:32