簡體   English   中英

Android - Jacoco 沒有正確生成 xml 報告

[英]Android - Jacoco does not generate xml report properly

我們已經將 JaCoCo 插件集成到我們的 Android 項目中,用於通過 SonarQube 測量代碼覆蓋率。但是,它無法測量。 因為 SonarQube 期望覆蓋率報告為 XML 格式。 我們將自定義jacocoTestReport任務添加到 build.gradle(module)。 它生成一個 xml 文件,但不包含任何覆蓋信息。 你遇到過這樣的問題嗎? 如果有,你有什么解決辦法嗎?

build.gradle(根)

classpath "org.jacoco:org.jacoco.core:0.8.5"

build.gradle(模塊)

apply plugin: 'jacoco'




...




task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) {
reports {
    xml.enabled = true
    html.enabled = true
}

def fileFilter = ['**/R.class',
                  '**/R$*.class',
                  '**/BuildConfig.*',
                  '**/Manifest*.*',
                  '**/*Test*.*',
                  'android/**/*.*']
def debugTree = fileTree(dir: "${buildDir}/intermediates/classes/debug", excludes: fileFilter)
def mainSrc = "${project.projectDir}/src/main/java"

getSourceDirectories().setFrom(files([mainSrc]))
getClassDirectories().setFrom(files([debugTree]))
getExecutionData().setFrom(fileTree(dir: "$buildDir", includes: [
        "jacoco/testDebugUnitTest.exec",
        "outputs/code-coverage/connected/*coverage.ec"
]))

Output:

在此處輸入圖像描述

在此處輸入圖像描述

Baseline: AGP 7.1.2 +, jacoco 0.88, hilt 2.42,很多你要更新jacoco.gradle文件。

 apply plugin: 'jacoco'
    jacoco {
    toolVersion = '0.8.7'
    }

    task jacocoTestReport { self ->
    build.dependsOn self
    }

    //Use this method to generate the HTML and XML coverage report files for 
    Unit and UI test cases
    android.testVariants.all {
    def variant = it.testedVariant
    def variantName = variant.name.capitalize()
    def unitTestTask = "test${variantName}UnitTest"
    def androidTestCoverageTask = "create${variantName}CoverageReport"
    tasks.create(name: "jacoco${name}TestReport", type: JacocoReport)

            { self ->
                group = 'Reporting'
                description = "Generates Jacoco coverage reports on the 
    ${variant.name} variant"

                reports {
                    xml.enabled(true)
                    html.enabled(true)
                }

                def excludes = [
                        // data binding
                        'android/databinding/**/*.class',
                        '**/android/databinding/*Binding.class',
                        '**/android/databinding/*',
                        '**/androidx/databinding/*',
                        '**/BR.*',
                        // android
                        '**/R.class',
                        '**/R$*.class',
                        '**/BuildConfig.*',
                        '**/Manifest*.*',
                        '**/*Test*.*',
                        'android/**/*.*',
                        // butterKnife
                        '**/*$ViewInjector*.*',
                        '**/*$ViewBinder*.*',
                        // dagger
                        '**/*_MembersInjector.class',
                        '**/Dagger*Component.class',
                        '**/Dagger*Component$Builder.class',
                        '**/*Module_*Factory.class',
                        '**/di/module/*',
                        '**/*_Factory*.*',
                        '**/*Module*.*',
                        '**/*Dagger*.*',
                        '**/*Hilt*.*',
                        // kotlin
                        '**/*MapperImpl*.*',
                        '**/*$ViewInjector*.*',
                        '**/*$ViewBinder*.*',
                        '**/BuildConfig.*',
                        '**/*Component*.*',
                        '**/*BR*.*',
                        '**/Manifest*.*',
                        '**/*$Lambda$*.*',
                        '**/*Companion*.*',
                        '**/*Module*.*',
                        '**/*Dagger*.*',
                        '**/*Hilt*.*',
                        '**/*MembersInjector*.*',
                        '**/*_MembersInjector.class',
                        '**/*_Factory*.*',
                        '**/*_Provide*Factory*.*',
                        '**/*Extensions*.*',
                        // sealed and data classes
                        '**/*$Result.*',
                        '**/*$Result$*.*'
                ]

                def javaClasses = fileTree(dir: 
    variant.javaCompileProvider.get().destinationDir,
                        excludes: excludes)
                def kotlinClasses = fileTree(dir: "${buildDir}/tmp/kotlin- 
   classes/${variant.name}",
                        excludes: excludes)
                classDirectories.setFrom(files([
                        javaClasses,
                        kotlinClasses
                ]))
                def variantSourceSets = "${project.projectDir}/src/main/java"
                sourceDirectories.setFrom(project.files(variantSourceSets))
                def androidTestsData = fileTree(dir: 
    "${buildDir}/outputs/code_coverage/${variant.name}AndroidTest/connected/", 
    includes: ["**/*.ec"])
                executionData(files([                        
"$project.buildDir/outputs/unit_test_code_coverage/${variant.name}UnitTest/test 
   ${variantName}UnitTest.exec",
                        androidTestsData
                ]))

                dependsOn unitTestTask, androidTestCoverageTask
                jacocoTestReport.dependsOn self
            }
      }

由於 AGP 正在更新,構建目錄中的路徑已更改。

//替換這段代碼

executionData.from = fileTree(dir: buildDir, includes: [
                        "jacoco/test${variantName}UnitTest.exec",
                        "/outputs/code_coverage/${variant.name}AndroidTest/connected/*coverage.ec"
                ])

//到這段代碼

 def androidTestsData = fileTree(dir: "${buildDir}/outputs/code_coverage/${variant.name}AndroidTest/connected/", includes: ["**/*.ec"])
            executionData(files([
                    "$project.buildDir/outputs/unit_test_code_coverage/${variant.name}UnitTest/test${variantName}UnitTest.exec",
                    androidTestsData
            ]))

經過一番谷歌搜索,我終於解決了這個問題。 源和 class 目錄的路徑不正確。 正確的路徑應該是這樣的:

            def javaClasses = fileTree(dir: variant.javaCompileProvider.get().destinationDir,
                    excludes: fileFilter)
            def kotlinClasses = fileTree(dir: "${buildDir}/tmp/kotlin-classes/${variantName}",
                    excludes: fileFilter)

            classDirectories.setFrom(files([
                    javaClasses,
                    kotlinClasses
            ]))

            def variantSourceSets = variant.sourceSets.java.srcDirs.collect { it.path }.flatten()
            sourceDirectories.setFrom(project.files(variantSourceSets))

問候,

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM