【问题标题】:Exclude from coverage on multimodule project using jacoco and gradle从使用 jacoco 和 gradle 的多模块项目中排除
【发布时间】:2020-04-14 18:34:41
【问题描述】:

我一直试图从 jacoco 生成的覆盖率报告中排除某些类和/或包。我以前和 jacoco 合作过,但它不是一个多模块项目,所以我尝试翻译配置并将其导出到模块,但到目前为止,报告完全忽略了我的排除路径。

我尝试了很多解决方案,例如:

我不知道我做错了什么,我对 gradle 不是很了解,而且我发现的几乎每个文档/示例都使用单个模块项目。 我创建了一个小项目并推送到gitlab,以便您更好地查看。

期望的结果是能够直接向模块添加更多路径或类。

非常感谢您能提供的任何帮助。


代码 sn-ps:

Root build.gradle.kts

plugins {
    kotlin("jvm") version "1.3.71"
    jacoco
}

repositories {
    mavenCentral()
}

defaultTasks("clean", "build", "test")

allprojects {
    apply(plugin = "org.jetbrains.kotlin.jvm")
    apply(plugin = "jacoco")

    group = "org.example"
    version = "1.0-SNAPSHOT"

    repositories {
        mavenCentral()
    }

    jacoco {
        toolVersion = "0.8.5"
    }

    dependencies {
        implementation(kotlin("stdlib-jdk8"))
        testImplementation("org.testng:testng:6.14.3")
    }

    configure<JavaPluginConvention> {
        sourceCompatibility = JavaVersion.VERSION_1_8
    }

    tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile::class) {
        kotlinOptions {
            jvmTarget = "1.8"
        }
    }

    tasks.test {
        useTestNG()
        finalizedBy("jacocoTestReport")
    }
}

tasks.jacocoTestReport {
    val sourceDirs = sourceSets.main.get().allSource.srcDirs
    additionalSourceDirs.setFrom(sourceDirs)
    sourceDirectories.setFrom(sourceDirs)
    classDirectories.setFrom(sourceSets.main.get().output)
    reports {
        html.isEnabled = true
        xml.isEnabled = false
        csv.isEnabled = false
    }
}

tasks.register<JacocoReport>("jacocoRootReport") {
    val sourceDirs = subprojects.map { project -> project.sourceSets.main.get().allSource.srcDirs }
    dependsOn(subprojects.map { project -> project.tasks.test })
    sourceDirectories.setFrom(sourceDirs)
    additionalSourceDirs.setFrom(sourceDirs)
    classDirectories.setFrom(subprojects.map { project -> project.sourceSets.main.get().output })
    executionData.setFrom(subprojects.map { project -> project.tasks.jacocoTestReport.get().executionData })
    reports {
        html.isEnabled = true
        xml.isEnabled = false
        csv.isEnabled = false
    }
}

tasks.test {
    finalizedBy("jacocoRootReport")
}

Module build.gradle.kts

dependencies {
    implementation(project(":api"))
}

tasks {
    getByName<JacocoReport>("jacocoTestReport") {
        afterEvaluate {
            classDirectories.setFrom(files(classDirectories.files.map {
                fileTree(it) {
                    exclude("org/example/AppClass.class")
                }
            }))
        }
    }
}

另外,任何关于其他任何事情的反馈都非常感谢,我正在努力学习/改进并可以使用一些:)。

[Edit #1] 刚刚将singlemodule branch 添加到按预期工作的同一仓库中,但在单模块模式下。

[Edit #2] 注意我使用jacoco: 0.8.5 gradle: 6.1Kotlin DSL (build.gradle.kts) 上的配置文件

【问题讨论】:

    标签: android kotlin gradle jacoco multi-module


    【解决方案1】:

    前段时间,我也被困在使用 Sonarqube 设置 JaCoCo 的过程中,并提出了 this article 这可能会对您有所帮助。

    这是jacoco.gradle文件的完整内容:

    apply plugin: 'jacoco'
    
    tasks.withType(Test) {
        jacoco.includeNoLocationClasses = true
        jacoco.excludes = ['jdk.internal.*'] // see related issue https://github.com/gradle/gradle/issues/5184#issuecomment-457865951
    }
    
    tasks.withType(Test) { jacoco.includeNoLocationClasses = true }
    
    project.afterEvaluate {
    
        (android.hasProperty('applicationVariants')
                ? android.'applicationVariants'
                : android.'libraryVariants').all { variant ->
            def variantName = variant.name
            def unitTestTask = "test${variantName.capitalize()}UnitTest"
            def uiTestCoverageTask = "create${variantName.capitalize()}CoverageReport"
    
            tasks.create(name: "${unitTestTask}Coverage", type: JacocoReport, dependsOn: [
                    "$unitTestTask",
                    "$uiTestCoverageTask",
                    ":module1:testDebugUnitTest",
                    ":module2:testDebugUnitTest",
                    ":moduleN:testDebugUnitTest",
            ]) {
                group = "Reporting"
                description = "Generate Jacoco coverage reports for the ${variantName.capitalize()} build"
    
                reports {
                    html.enabled = true
                    xml.enabled = true
                    csv.enabled = false
                }
    
                def fileFilter = [
                        '**/R.class',
                        '**/R$*.class',
                        '**/BuildConfig.*',
                        '**/Manifest*.*',
                        '**/*Test*.*',
                        '**/com/example/databinding/*',
                        '**/com/example/generated/callback/*',
                        '**/android/databinding/*',
                        '**/androidx/databinding/*',
                        '**/di/module/*',
                        '**/*MapperImpl*.*',
                        '**/*$ViewInjector*.*',
                        '**/*$ViewBinder*.*',
                        '**/BuildConfig.*',
                        '**/*Component*.*',
                        '**/*BR*.*',
                        '**/Manifest*.*',
                        '**/*$Lambda$*.*',
                        '**/*Companion*.*',
                        '**/*Module.*', /* filtering Dagger modules classes */
                        '**/*Dagger*.*',/* filtering Dagger-generated classes */
                        '**/*MembersInjector*.*',
                        '**/*_Factory*.*',
                        '**/*_Provide*Factory*.*',
                        '**/*Extensions*.*',
                        '**/*$Result.*', /* filtering `sealed` and `data` classes */
                        '**/*$Result$*.*'/* filtering `sealed` and `data` classes */
                        '**/*Args*.*', /* filtering Navigation Component generated classes */
                        '**/*Directions*.*' /* filtering Navigation Component generated classes */
                ]
    
                classDirectories.setFrom(files([
                        fileTree(dir: "${buildDir}/tmp/kotlin-classes/${variantName}", excludes: fileFilter),
                        fileTree(dir: "$project.rootDir/module1/build/tmp/kotlin-classes/debug", excludes: fileFilter),
                        fileTree(dir: "$project.rootDir/module2/build/tmp/kotlin-classes/debug", excludes: fileFilter),
                        fileTree(dir: "$project.rootDir/moduleN/build/tmp/kotlin-classes/debug", excludes: fileFilter),
                ]))
    
                def coverageSourceDirs = [
                        "$project.rootDir/app/src/main/java",
                        "$project.projectDir/src/${variantName}/java",
                        "$project.rootDir/module1/src/main/java",
                        "$project.rootDir/module2/src/main/java",
                        "$project.rootDir/moduleN/src/main/java"
                ]
                additionalSourceDirs.setFrom(files(coverageSourceDirs))
                sourceDirectories.setFrom(files(coverageSourceDirs))
    
                def uiTestsData = fileTree(dir: "${buildDir}/outputs/code_coverage/${variantName}AndroidTest/connected/", includes: ["**/*.ec"])
    
                executionData(files([
                        "$project.buildDir/jacoco/${unitTestTask}.exec",
                        uiTestsData,
                        "$project.rootDir/module1/build/jacoco/testDebugUnitTest.exec",
                        "$project.rootDir/module2/build/jacoco/testDebugUnitTest.exec",
                        "$project.rootDir/moduleN/build/jacoco/testDebugUnitTest.exec"
                ]))
            }
        }
    }
    

    您可以查看fileFilter 以获取更多过滤选项。

    然后在每个模块中,您必须像这样导入jacoco.gradle

    apply from: "jacoco.gradle"
    

    【讨论】:

    • 酷!我会试试看!非常感谢您的回复:)
    猜你喜欢
    • 2016-08-19
    • 1970-01-01
    • 1970-01-01
    • 2020-09-03
    • 2015-01-17
    • 2012-09-03
    • 2018-09-22
    • 2017-06-03
    • 1970-01-01
    相关资源
    最近更新 更多