Jacoco 在 Android 项目中通过单元测试报告 Kotlin 类 的覆盖率为 0

Jacoco is reporting 0 coverage of Kotlin classes by unit tests, in an Android project

我正在使用 Android Gradle 插件 3.0.0.

我正在将 Android 应用程序从 java 迁移到 kotlin。我的应用程序在 Java 和 Kotlin 中有 类,测试在 Java.

我运行./gradlew clean jacocoTestReport.

这 运行 包括单元测试 (src/test) 和仪器测试 (src/androidTest)。

jacoco 在 app/build/reports/jacoco/jacocoTestReport/html/index.html 中生成的报告没有显示 Kotlin 类 的覆盖范围,这确实被单元测试覆盖了。

该报告确实正确显示了仪器测试的覆盖率。

注意:我遇到了这些其他问题,它们并不完全相同:

我的应用模块 build.gradle 的相关部分:

apply plugin: 'jacoco'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
...
android {
    defaultConfig {
        sourceSets {
            main.java.srcDirs += "$projectDir/src/main/kotlin"
        }
    }

    testOptions {
        unitTests {
            all {
                jvmArgs '-noverify', '-ea'
            }
            includeAndroidResources = true
        }
    }
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    ....
}

jacoco {
    toolVersion '0.7.9'
}

task jacocoTestReport(type: JacocoReport, dependsOn: ["testDebugUnitTest", "createDebugCoverageReport"]) {
    reports {
        html.enabled = true
    }
    classDirectories = fileTree(
            dir: "${buildDir}",
            includes: ["tmp/kotlin-classes/debug/ca/rmen/android/poetassistant/**/*.class",
                       "intermediates/classes/debug/ca/rmen/android/poetassistant/**/*.class"],
            excludes: ["**/R.class", "**/R*.class", "**/Manifest.class", "**/Manifest*.class", "**/BuildConfig.class",
                       // ignore databinding generated code:
                       "**/ca/rmen/android/poetassistant/databinding/*.class",
                       ... other excludes ...
                       "**/ca/rmen/android/poetassistant/BR.class",
                       "**/com/android/**/*.class"])
    sourceDirectories = files("${project.projectDir}/src/main/java", "${project.projectDir}/src/main/kotlin")
    executionData = fileTree(
            dir: "${buildDir}",
            includes: [
                    "jacoco/testDebugUnitTest.exec",
                    "outputs/code-coverage/connected/*coverage.ec"
            ])
}

我必须按如下方式将 includeNoLocationClasses = true 添加到我的 gradle 文件中,以使 jacoco 报告通过单元测试反映 Kotlin 类 的覆盖率:

android {
    testOptions {
        unitTests {
            all {
                jvmArgs '-noverify', '-ea'
                jacoco {
                    includeNoLocationClasses = true
                }
            }
            includeAndroidResources = true
        }
    }
}

注意:此解决方案适用于来自命令行的 运行 测试,但当 运行 来自 Android Studio 的覆盖率时,我仍然获得 0% 的覆盖率。

在 jacoco.gradle 文件中添加以下行以获取 kotlin 类

            def kotlinDebugTree = fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug", excludes: fileFilter)

例如

def mainSrc = "${project.projectDir}/src/main/java"
            def debugTree = fileTree(dir: "${buildDir}/intermediates/classes/debug", excludes: fileFilter)
            def kotlinDebugTree = fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug", excludes: fileFilter)
            sourceDirectories.from = files([mainSrc])
            classDirectories.from = files([debugTree], [kotlinDebugTree])
            executionData.from = fileTree(dir: buildDir, includes: [
                    "jacoco/test${name}UnitTest.exec",
                    'outputs/code-coverage/connected/*coverage.ec'
            ])

添加此行后再次执行 jacoco 命令,它也会提供单元测试用例的覆盖率。