插桩测试是否有可能为库模块创建覆盖率?

Is it possible for Instrumented tests to create coverage for a library module?

我正在对我正在开发的应用程序进行模块化,自从将我的仪器测试拆分到应用程序模块后,我的覆盖率下降了 20% 以上。

应用程序被拆分为 appcorecustom,其中 core 是一个 android 库,其他 2 个模块是应用程序.该应用程序的大部分功能将存在于 core 中,目前主要通过仪器测试进行测试,这些测试现在位于 app.

有没有一种方法可以让应用程序模块中的仪器测试生成包含库模块源的覆盖率报告?

我查看了这个问题 ,它与我的困境非常相似,但这似乎已经过时了,因为 publishNonDefault 已被弃用并且什么都不做,因为图书馆现在发布所有变体

我的努力正在进行 this PR

这样的覆盖率下降很难完成模块化,我希望覆盖率保持不变post模块化。

编辑:我创建了一个复制项目here

从合并的可执行文件

查看 JacocoMerge task which can merge multiple jacoco execution files into a single file. You can then generate a JacocoReport

没有

只需将您的仪器测试添加到包含被测代码的模块即可。

由于这个 SO answer,我误以为仪器测试不能 运行 在库项目上,我建议进行编辑以反映最新的文档。

编辑:我后来找到了一个解决方案,但老实说它可能不应该使用,这是你应该走的路。仪器测试可能不应该用于开始覆盖,除非您坚持使用旧版,否则不要使用此页面上提供的解决方案。

查看JaCoCo plugin docs which show that a task named "jacocoTestReport" is added by the JaCoCo plugin. And you can see there's an "additionalSourceDirs" property on the JacocoReport任务

所以你可以做类似的事情

apply plugin: 'java-library' 
apply plugin: 'jacoco' 
evaluationDependsOn ':another-project'
tasks.withType(JacocoReport) {
   def otherSourceSet = project(':another-project').sourceSets.main
   additionalSourceDirs.from otherSourceSet.allJava
   additionalClassDirs.from otherSourceSet.output
} 

最终的答案来自 here 所以所有的功劳都归功于他们。在这里发布文件的内容供任何人在未来寻找

apply plugin: 'jacoco'

jacoco {
    toolVersion = "$jacocoVersion"
}

tasks.withType(Test) {
    jacoco.includeNoLocationClasses = true
}

task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'createDebugCoverageReport']) {

    group "Reporting"
    description "Generate Jacoco coverage reports."

    reports {
        xml.enabled = true
        html.enabled = true
        html.destination file("${rootProject.buildDir}/coverage-report")
    }

    def javaClasses = []
    def kotlinClasses = []
    def javaSrc = []
    def kotlinSrc = []
    def execution = []

    def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*']

    rootProject.subprojects.each { proj ->
        javaClasses   << fileTree(dir: "$proj.buildDir/intermediates/javac/debug", excludes: fileFilter)
        kotlinClasses << fileTree(dir: "$proj.buildDir/tmp/kotlin-classes/debug", excludes: fileFilter)
        javaSrc       << "$proj.projectDir/src/main/java"
        kotlinSrc     << "$proj.projectDir/src/main/kotlin"
        execution     << fileTree(dir: proj.buildDir,
                includes: ['jacoco/testDebugUnitTest.exec',
                           'outputs/code_coverage/debugAndroidTest/connected/**/*.ec'])
    }

    sourceDirectories = files([javaSrc, kotlinSrc])
    classDirectories = files([javaClasses, kotlinClasses])

    print execution

    executionData = files(execution)

    doLast() {
        print "file://${reports.html.destination}/index.html"
    }
}

FileFilter 可能需要对现代 Android 应用程序进行一些改进,例如 Dagger/ViewBinding.

我在我的 app/build.gradle 中应用了这个,在 运行 gradlew jacocoTestReport 之后 [projRoot]/build/coverage-report 中出现了完整报道的报告。

已使用解决方案更新了 Repro 项目。