簡體   English   中英

Jacoco和單元測試代碼覆蓋率使用android-gradle-plugin> = 1.1

[英]Jacoco and Unit Tests Code Coverage with android-gradle-plugin >= 1.1

我最近開始在其中一個項目中集成android-gradle-plugin 1.1.0。 該項目使用robolectric 2.4運行單元測試。

這是一個具有非常復雜的依賴關系的多模塊項目(某些模塊依賴於其他模塊)。 像這樣:

--> application-module (dependsOn: module1, module2, module-core)
    --> module1 (dependsOn: module-core)
    --> module2 (dependsOn: module-core)
    --> module-core (dependsOn: module3, module4)
        --> module3 (library dependencies)
        --> module4 (library dependencies)

有關更清晰的圖片,請參見jacoco-example項目。

我試圖集成JaCoCo為單元測試生成報告,但是在我看來,它僅運行androidTests ,而基本上是儀器測試。

經過一番谷歌搜索后,我在GitHub和其他文章上遇到了一些項目,但是它們主要集中在android-gradle-plugin版本上,或者在這里使用了其他第三方插件,例如android-unit-test

可能是我失去了使用Google的能力。 但是有人可以指出我可以在android gradle插件中找到有關新內容的文檔以及如何僅針對單元測試運行jacoco任務的方向嗎?

更新

nenick的示例中采用了腳本:

apply plugin: "jacoco"

configurations {
    jacocoReport
}

task jacocoReport(dependsOn: 'testDebug') << {
    ant {
        taskdef(name:'jacocoreport',
                classname: 'org.jacoco.ant.ReportTask',
                classpath: configurations.jacocoReport.asPath)

        mkdir dir: "${buildDir}/test-coverage-report"
        mkdir dir: "${buildDir}/reports/jacoco/test/"

        jacocoreport {
            executiondata = files("${buildDir}/jacoco/testDebug.exec")

            structure(name: "${rootProject.name}") {
                classfiles {
                    fileset (dir: "${buildDir}/intermediates/classes/debug") {
                        //exclude(name: '**/*_*.class')
                        exclude(name: '**/R.class')
                        exclude(name: '**/R$*.class')
                        exclude(name: '**/BuildConfig.class')
                    }
                }

                sourcefiles {
                    fileset dir: "src/main/java"
                    fileset dir: "${buildDir}/generated/source/buildConfig/debug"
                    fileset dir: "${buildDir}/generated/source/r/debug"
                }
            }

            xml destfile: "${buildDir}/reports/jacoco/test/jacocoTestReport.xml"
            html destdir: "${buildDir}/test-coverage-report/"
        }
    }
}

dependencies {
    jacocoReport 'org.jacoco:org.jacoco.ant:0.7.2.201409121644'
}

之后,。/ ./gradlew jacocoReport執行並生成報告,但是它顯示0(零)測試覆蓋率,這是不可能的,因為至少所有類中的一半都經過了測試。

UPDATE_2

試了這個例子 將下一個任務添加到我的gradle構建文件之一:

task jacocoTestReport(type:JacocoReport, dependsOn: "testDebug") {
    group = "Reporting"
    description = "Generate Jacoco coverage reports"

    classDirectories = fileTree(
            dir: "${buildDir}/intermediates/classes/debug",
            excludes: ['**/R.class',
                       '**/R$*.class',
                       '**/*$ViewInjector*.*',
                       '**/BuildConfig.*',
                       '**/Manifest*.*']
    )

    sourceDirectories = files("${buildDir.parent}/src/main/java")
    additionalSourceDirs = files([
            "${buildDir}/generated/source/buildConfig/debug",
            "${buildDir}/generated/source/r/debug"
    ])
    executionData = files("${buildDir}/jacoco/testDebug.exec")

    reports {
        xml.enabled = true
        html.enabled = true
    }
}

同樣的問題,報告已生成,但代碼覆蓋率仍為零。

UPDATE_3

它表明UPDATE_2中的任務有效,但僅適用於帶有Apply apply plugin: 'com.android.application'的模塊apply plugin: 'com.android.application' (報告正確生成了)。 但是對於屬於android庫的模塊( apply plugin: 'com.android.library' ),報告顯示的覆蓋率為零,盡管這些模塊比應用程序模塊包含更多的測試。

UPDATE_4

創建了一個簡單的示例項目來演示我的問題。 當前,如果您運行./gradlew jacocoReport ,則會生成報告,但不會顯示模塊項目的測試覆蓋率。 看到這個鏈接

簡短說明:當測試為AndroidUnitTests(白色JUnit 4和Robolectric)時,JaCoCo報告顯示了所有模塊的覆蓋范圍。

有任何想法嗎?

麻煩之后,我決定為此創建一個開源Gradle插件

根build.gradle

buildscript {
    repositories {
        mavenCentral() // optional if you have this one already
    }
    dependencies {
        classpath 'com.vanniktech:gradle-android-junit-jacoco-plugin:0.8.0'
    }
}

apply plugin: 'com.vanniktech.android.junit.jacoco'

然后簡單地執行

./gradlew jacocoTestReportDebug

它將在調試模式下運行JUnit測試,然后在相應的構建目錄中以xml和html格式提供Jacoco輸出。

它還支持口味。 有兩種口味的紅色和藍色將創建這些任務

  • jacocoTestReportRedDebug
  • jacocoTestReportBlueDebug
  • jacocoTestReportRedRelease
  • jacocoTestReportBlueRelease

經過一些額外的搜索后,我偶然發現了這個項目,我不得不進行一些修改,以使解決方案適用於我的項目類型,但是現在可以正確生成測試覆蓋率報告。

我已將采用的更改推送到我的示例github存儲庫中,以防將來有人遇到類似問題。

我使用此博客文章為gradle 1.2設置了單元測試。 然后,我整理了在這里和其他地方找到的信息,以將代碼覆蓋率添加到獨立模塊而不是整個項目中。 在我的庫模塊build.gradle文件中,添加了以下內容:

apply plugin: 'jacoco'

def jacocoExcludes = [
        'com/mylibrary/excludedpackage/**'
]

android {
    ...
}

android.libraryVariants.all { variant ->
    task("test${variant.name.capitalize()}WithCoverage", type: JacocoReport, dependsOn: "test${variant.name.capitalize()}") {
        group = 'verification'
        description = "Run unit test for the ${variant.name} build with Jacoco code coverage reports."

        classDirectories = fileTree(
                dir: variant.javaCompile.destinationDir,
                excludes: rootProject.ext.jacocoExcludes.plus(jacocoExcludes)
        )
        sourceDirectories = files(variant.javaCompile.source)
        executionData = files("${buildDir}/jacoco/test${variant.name.capitalize()}.exec")

        reports {
            xml.enabled true
            xml.destination "${buildDir}/reports/jacoco/${variant.name}/${variant.name}.xml"
            html.destination "${buildDir}/reports/jacoco/${variant.name}/html"
        }
    }
}

在我的項目build.gradle文件中,添加了常見的排除項:

ext.jacocoExcludes = [
    'android/**',
    '**/*$$*',
    '**/R.class',
    '**/R$*.class',
    '**/BuildConfig.*',
    '**/Manifest*.*',
    '**/*Service.*'
]

另外,看起來單元標記的代碼覆蓋范圍可能會在將來的版本144664中構建

警告:這是駭客! 使用上面的配置,我整理了一個技巧,根據選擇的構建任務在應用程序和庫之間切換android插件。 這對我來說效果很好,因為我最終不會在設置應用程序模式的情況下提交代碼。

// dynamically change the android plugin to application if we are running unit tests or test reports.
project.ext.androidPlugin = 'com.android.library'
for (String taskName : project.gradle.startParameter.taskNames) {
    if (taskName.contains('UnitTest') || taskName.contains('jacocoTestReport')) {
        project.ext.androidPlugin = 'com.android.application'
        break
    }
}

logger.lifecycle("Setting android pluging to ${project.ext.androidPlugin}")
apply plugin: project.ext.androidPlugin

...

apply plugin: 'jacoco'

configurations {
    jacocoReport
}

task jacocoTestReport(type:JacocoReport, dependsOn: "testDebug") {
    group = "Reporting"
    description = "Generate Jacoco coverage reports"

    classDirectories = fileTree(
            dir: "${buildDir}/intermediates/classes/debug",
            excludes: ['**/R.class',
                       '**/R$*.class',
                       '**/*$ViewInjector*.*',
                       '**/BuildConfig.*',
                       '**/Manifest*.*']
    )

    sourceDirectories = files("${buildDir.parent}/src/main/java")
    additionalSourceDirs = files([
            "${buildDir}/generated/source/buildConfig/debug",
            "${buildDir}/generated/source/r/debug"
    ])
    executionData = files("${buildDir}/jacoco/testDebug.exec")

    reports {
        xml.enabled = true
        html.enabled = true
    }
}

希望android工具團隊盡快解決此問題。

我終於能夠看到使用Android Studio 1.1進行JUnit測試的代碼覆蓋率。

jacoco.gradle

apply plugin: 'jacoco'

jacoco {
    toolVersion "0.7.1.201405082137"
}

def coverageSourceDirs = [
        "$projectDir/src/main/java",
]

task jacocoTestReport(type: JacocoReport, dependsOn: "testDebug") {
    group = "Reporting"
    description = "Generate Jacoco coverage reports after running tests."
    reports {
        xml.enabled = true
        html.enabled = true
    }
    classDirectories = fileTree(
            dir: './build/intermediates/classes/debug',
            excludes: ['**/R*.class',
                       '**/*$InjectAdapter.class',
                       '**/*$ModuleAdapter.class',
                       '**/*$ViewInjector*.class'
            ]
    )
    sourceDirectories = files(coverageSourceDirs)
    executionData = files("$buildDir/jacoco/testDebug.exec")
    // Bit hacky but fixes https://code.google.com/p/android/issues/detail?id=69174.
    // We iterate through the compiled .class tree and rename $$ to $.
    doFirst {
        new File("$buildDir/intermediates/classes/").eachFileRecurse { file ->
            if (file.name.contains('$$')) {
                file.renameTo(file.path.replace('$$', '$'))
            }
        }
    }
}

然后在模塊的build.gradle文件中(我將其放在androiddependencies之間):

apply from: '../jacoco.gradle'

也在androiddefaultConfig塊中。 我添加了此內容(不知道是否有必要,但是我從此Blog中獲得了此內容):

android {
    defaultConfig {
        testHandleProfiling true
        testFunctionalTest true
    }
}

請享用。

您可以嘗試使用此Gradle插件: https : //github.com/arturdm/jacoco-android-gradle-plugin

基本上,您需要做的就是像這樣應用它:

buildscript {
  repositories {
    jcenter()
  }
  dependencies {
    classpath 'com.dicedmelon.gradle:jacoco-android:0.1.1'
  }
}

apply plugin: 'com.android.library' // or 'com.android.application'
apply plugin: 'jacoco-android'

結果,您應該為每個變量獲得一個JacocoReport任務。 運行以下命令以生成所有代碼覆蓋率報告。

$ ./gradlew jacocoTestReport

我解決了JaCoCo的問題,並使其與最新的gradle android插件1.1.3一起使用

具有最新gradle腳本的項目: https : //github.com/OleksandrKucherenko/meter

參考文獻:

如何在Android Studio單元測試中附加自己的實現而不是Mocks? https://plus.google.com/117981280628062796190/posts/8jWV22mnqUB

對嘗試在Android構建中使用JaCoCo覆蓋范圍的所有人的一個小提示...意外發現!!! https://plus.google.com/117981280628062796190/posts/RreU44qmeuP

JaCoCo用於單元測試的XML / HTML報告 https://plus.google.com/u/0/+OleksandrKucherenko/posts/6vNWkkLed3b

我正面臨着像你一樣的問題。 今天我確實完全刪除了android studio,android sdk,gradle。 然后重新安裝所有內容。 之后,我只添加了應用程序build.gradle。

debug {testCoverageEnabled true}然后運行./gradlew connectedChec。 一切工作正常。 Android studio默認的Jacoco對我來說工作正常。 我認為也可以創建一個jacocoTestReport Task然后創建代碼覆蓋率。我不知道為什么gradle和android studio以前無法正常工作。

請創建一個示例,我可以看看。 我想這是一些缺少的路徑配置。

  • 包括所有覆蓋率文件(* .exec)
  • 添加所有源路徑(module / src / main / java)
  • 添加所有類路徑(模塊/構建/中間/類/調試)

這里有兩個例子

暫無
暫無

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

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