使用 Gadle kotlin 为多模块 Android 代码库设置 jacoco

Pet*_*rus 8 android gradle jacoco kotlin android-jacoco

我目前正在我的团队构建的 Android 代码库中设置 Jacoco。我在 Android 方面没有太多经验,但我之前已经在 Spring Boot 代码库中设置了 Jacoco,以便我可以跟踪 Sonarqube 中的测试覆盖率。但我在 Android 代码库中遇到了困难。

\n

所以目录布局看起来像这样

\n
MyApp/\n\xe2\x94\x9c\xe2\x94\x80 app/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 build/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 src/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 build.gradle.kts\n\xe2\x94\x9c\xe2\x94\x80 buildSrc/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 build.gradle.kts\n\xe2\x94\x9c\xe2\x94\x80 modules/\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 module1/\n\xe2\x94\x82  \xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 src/\n\xe2\x94\x82  \xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 build.gradle.kts\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 module2/\n\xe2\x94\x82  \xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 src/\n\xe2\x94\x82  \xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 build.gradle.kts\n\xe2\x94\x9c\xe2\x94\x80 build.gradle.kts\n\xe2\x94\x9c\xe2\x94\x80 gradle.properties\n\xe2\x94\x9c\xe2\x94\x80 gradlew\n\xe2\x94\x9c\xe2\x94\x80 settings.gradle.kts\n
Run Code Online (Sandbox Code Playgroud)\n

我尝试添加jacocoMyApp/build.gradle.kts.

\n
plugins {\n    id(Dependencies.Plugins.androidApplication) version Dependencies.Versions.androidAppplication apply false\n    id(Dependencies.Plugins.androidLibrary) version Dependencies.Versions.androidLibrary apply false\n    id(Dependencies.Plugins.hilt) version Dependencies.Versions.hilt apply false\n    id(Dependencies.Plugins.openApi) version Dependencies.Versions.openApi\n    id(Dependencies.Plugins.kotlinAndroid) version Dependencies.Versions.kotlinAndroid apply false\n    id(Dependencies.Plugins.sonarqube) version Dependencies.Versions.sonarqube\n    \n    id("jacoco")\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我尝试执行bash gradlew test jacocoTestReport但它说

\n
Task \'jacocoTestReport\' not found in root project \'MyApp\' and its subprojects.\n
Run Code Online (Sandbox Code Playgroud)\n

我尝试在每个 JaCoco 插件文档中添加以下行MyApp/build.gradle.ktshttps://docs.gradle.org/current/userguide/jacoco_plugin.html

\n
tasks.test {\n    finalizedBy(tasks.jacocoTestReport) // report is always generated after tests run\n}\ntasks.jacocoTestReport {\n    dependsOn(tasks.test) // tests are required to run before generating the report\n}\n
Run Code Online (Sandbox Code Playgroud)\n

但输出如下所示

\n
Script compilation errors:\n\n  Line 12: tasks.test {\n                 ^ Unresolved reference: test\n\n  Line 13:     finalizedBy(tasks.jacocoTestReport)                                              \n               ^ Unresolved reference: finalizedBy\n
Run Code Online (Sandbox Code Playgroud)\n

我在Spring Boot项目中做了类似的配置,之前运行正常。但在这里它甚至无法检测任务jacocoTestReport

\n

我做错了什么?

\n

Von*_*onC 3

在传统的 Java 或 Kotlin JVM 项目中,有一个测试任务,可通过tasks.test.

然而,在 Android 项目中,并没有单一的test任务。相反,有多个测试任务,每个测试任务对应一个构建变体。测试任务被命名为test<Variant>UnitTest. 例如,您可能有testDebugUnitTesttestReleaseUnitTest

当您尝试tasks.test在 Android 项目中访问时,会导致“未解析的引用:测试”错误,因为没有名为 的任务test

类似地,finalizedBy(tasks.jacocoTestReport)是一种指定任务依赖关系的方法,表示该jacocoTestReport任务应始终在该任务之后运行testtest但是,由于Android 项目中没有任务,因此会导致“ Unresolved reference: finalizedBy”错误。


在“如何根据存在的插件向子项目添加插件? ”之后,您可能需要在根目录中创建一个 Jacoco 设置build.gradle.kts,自动为使用 Android 插件的每个模块应用正确的 Jacoco 设置。

使用Gradle DLS 脚本

import org.gradle.testing.jacoco.tasks.JacocoReport

plugins {
    // your existing plugins...

    id("jacoco")
}

// rest of your configurations...

subprojects { subproject ->
    subproject.plugins.withId(Dependencies.Plugins.androidApplication) {
        setupJacoco(subproject)
    }
    subproject.plugins.withId(Dependencies.Plugins.androidLibrary) {
        setupJacoco(subproject)
    }
}


fun setupJacoco(project: Project) {
    project.tasks.register("jacocoTestReport", JacocoReport::class.java) { task ->
        task.group = "Reporting"
        task.description = "Generate Jacoco coverage reports after running tests."
        task.reports {
            xml.isEnabled = true
            html.isEnabled = true
        }
        task.executionData.setFrom(
            project.fileTree(project.buildDir).apply {
                include("**/jacoco/*.exec")
            }
        )
        task.sourceDirectories.setFrom(
            project.files(
                project.extensions.getByType<SourceSetContainer>().getByName("main").allSource.srcDirs
            )
        )
        task.classDirectories.setFrom(
            project.fileTree(
                project.extensions.getByType<SourceSetContainer>().getByName("main").output.classesDirs
            )
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

该脚本将检查构建中的每个子项目。如果子项目应用了您的 ID(例如Dependencies.Plugins.androidApplicationDependencies.Plugins.androidLibrary插件),它会为该子项目添加 Jacoco 任务。
对于每个项目,添加一个jacocoTestReport生成 Jacoco 报告的任务。

需要注意的一件重要事情是,Android Gradle 插件应用程序/库模块的每个构建变体创建一个任务。test例如,如果您有debugrelease构建类型,Android Gradle 插件将创建testDebugUnitTesttestReleaseUnitTest任务。

这意味着,您需要运行特定的test任务,然后jacocoTestReport像这样:

# Do this once, after making changes to your build.gradle.kts 
./gradlew --refresh-dependencies

# Then, each time you want to generate the report
./gradlew module1:testDebugUnitTest module1:jacocoTestReport
Run Code Online (Sandbox Code Playgroud)

这将运行单元测试module1,然后生成 Jacoco 报告。请注意,如果您使用的是产品风格,您可能有两种以上类型的test任务(例如,testFreeDebugUnitTesttestPaidDebugUnitTest等),因此请相应地调整您的命令以适合您的项目配置。