繁体   English   中英

Powermock Jacoco Gradle 0% 覆盖率 Android 项目

[英]Powermock Jacoco Gradle 0% Coverage For Android Project

我们有一个 Android 项目,我们在一些测试用例中使用 Powermock,在覆盖率报告中使用 Jacoco。 我们注意到我们的一些类返回为0%覆盖率,尽管它们确实被覆盖了。 我们还针对受影响的课程观察到以下消息。

"Classes ... do no match with execution data."

一些在线搜索表明, Powermock 和 Jacoco 不能很好地发挥作用,而离线仪器是一种可能的解决方法。

有没有人以前在android项目中使用过gradle离线检测脚本?

事后看来,我想这可以通过足够的安卓体验和在线阅读来解决。 然而,当它落在我的腿上时,我(现在仍然)对 Android、gradle 和 groovy 还比较陌生,所以我正在为下一个我写这篇文章:-D

简而言之摘自 jacoco 论坛

  • 源文件被编译成非检测类文件
  • 非检测类文件被检测(离线预检测,或由 Java 代理在运行时自动检测)
  • 执行收集到 exec 文件中的检测类
  • 报告使用从 exec 文件和原始非检测类文件的分析中获得的信息来修饰源文件
  • 消息“ Classes ... do no match with execution data. ”在报告生成期间意味着用于生成报告的类文件与检测之前的类不同。

解决方案

Jacoco Offline Instrumentation页面在此摘录中提供了离线检测应该发生的主要步骤:

对于此类场景,可以使用 JaCoCo 预先检测类文件,例如使用仪器 Ant 任务。 在运行时,预先检测的类需要在类路径上,而不是原始类。 此外 jacocoagent.jar 必须放在类路径上。

下面的脚本正是这样做的:

    apply plugin: 'jacoco'

configurations {
    jacocoAnt
    jacocoRuntime
}

jacoco {
    toolVersion = "0.8.1"
}

def offline_instrumented_outputDir = "$buildDir.path/intermediates/classes-instrumented/debug"

tasks.withType(Test) {
    jacoco.includeNoLocationClasses = true
}

def coverageSourceDirs = [
        'src/main/java'
]

task jacocoTestReport(type: JacocoReport, dependsOn: "test") {
    group = "Reporting"

    description = "Generate Jacoco coverage reports"

    classDirectories = fileTree(
            dir: 'build/intermediates/classes/debug',
            excludes: ['**/R.class',
                       '**/R$*.class',
                       '**/BuildConfig.*',
                       '**/MainActivity.*']
    )

    sourceDirectories = files(coverageSourceDirs)
    executionData = files('build/jacoco/testDebugUnitTest.exec')
}

jacocoTestReport {
    reports {
        xml.enabled  true
        html.enabled  true
        html.destination file("build/test-results/jacocoHtml")
    }
}

/* This task is used to create offline instrumentation of classes for on-the-fly instrumentation coverage tool like Jacoco. See jacoco classId
     * and Offline Instrumentation from the jacoco site for more info.
     *
     * In this case, some classes mocked using PowerMock were reported as 0% coverage on jacoco & Sonarqube. The issue between PowerMock and jacoco
     * is well documented, and a possible solution is offline Instrumentation (not so well documented for gradle).
     *
     * In a nutshell, this task:
     *  - Pre-instruments the original *.class files
     *  - Puts the instrumented classes path at the beginning of the task's classpath (for report purposes)
     *  - Runs test & generates a new exec file based on the pre-instrumented classes -- as opposed to on-the-fly instrumented class files generated by jacoco.
     *
     * It is currently not implemented to run prior to any other existing tasks (like test, jacocoTestReport, etc...), therefore, it should be called
     * explicitly if Offline Instrumentation report is needed.
     *
     *  Usage: gradle clean & gradle createOfflineInstrTestCoverageReport & gradle jacocoTestReport
     *   - gradle clean //To prevent influence from any previous task execution
     *   - gradle createOfflineInstrTestCoverageReport //To generate *.exec file from offline instrumented class
     *   - gradle jacocoTestReport //To generate html report from newly created *.exec task
     */
task createOfflineTestCoverageReport(dependsOn: ['instrument', 'testDebugUnitTest']) {
    doLast {
        ant.taskdef(name: 'report',
                classname: 'org.jacoco.ant.ReportTask',
                classpath: configurations.jacocoAnt.asPath)
        ant.report() {
            executiondata {
                ant.file(file: "$buildDir.path/jacoco/testDebugUnitTest.exec")
            }
            structure(name: 'Example') {
                classfiles {
                    fileset(dir: "$project.buildDir/intermediates/classes/debug")
                }
                sourcefiles {
                    fileset(dir: 'src/main/java')
                }
            }
            //Uncomment if we want the task to generate jacoco html reports. However, the current script does not exclude files.
            //An alternative is to used jacocoTestReport after this task finishes
            //html(destdir: "$buildDir.path/reports/jacocoHtml")
        }
    }
}

/*
 * Part of the Offline Instrumentation process is to add the jacoco runtime to the class path along with the path of the instrumented files.
 */
gradle.taskGraph.whenReady { graph ->
    if (graph.hasTask(instrument)) {
        tasks.withType(Test) {
            doFirst {
                systemProperty 'jacoco-agent.destfile', buildDir.path + '/jacoco/testDebugUnitTest.exec'
                classpath = files(offline_instrumented_outputDir) + classpath + configurations.jacocoRuntime
            }
        }
    }
}

/*
 *  Instruments the classes per se
 */
task instrument(dependsOn:'compileDebugUnitTestSources') {
    doLast {
        println 'Instrumenting classes'

        ant.taskdef(name: 'instrument',
                classname: 'org.jacoco.ant.InstrumentTask',
                classpath: configurations.jacocoAnt.asPath)

        ant.instrument(destdir: offline_instrumented_outputDir) {
            fileset(dir: "$buildDir.path/intermediates/classes/debug")
        }
    }
}

用法

  • 可以将脚本复制到单独的文件中。 例如: jacoco.gradle

  • 在 build.gradle 中引用 jacoco 文件。 例如: apply from: jacoco.gradle

  • 确保正确的依赖关系: jacocoAnt 'org.jacoco:org.jacoco.ant:0.8.1:nodeps'

  • 在命令行中运行: gradle clean & gradle createOfflineTestCoverageReport & gradle jacocoTestReport

    gradle clean将清除任何以前的 gradle 执行工件

    gradle createOfflineTestCoverageReport将创建离线检测,更改类路径的顺序,生成 .exec 文件

    gradle jacocoTestReport将运行测试并根据之前生成的 .exec 文件生成 jacoco 报告

失落的感觉?

我已经将 github Jacoco Powermock Android项目与示例脚本放在一起,以重现和解决问题。 它还包含有关解决方案的更多信息。

参考

https://github.com/powermock/powermock/wiki/Code-coverage-with-JaCoCo
https://www.jacoco.org/jacoco/trunk/doc/classids.html
https://www.jacoco.org/jacoco/trunk/doc/offline.html
https://github.com/powermock/powermock-examples-maven/tree/master/jacoco-offline
https://automated-testing.info/t/jacoco-offline-instrumentations-for-android-gradle/20121
https://stackoverflow.com/questions/41370815/jacoco-offline-instrumentation-gradle-script/42238982#42238982
https://groups.google.com/forum/#!msg/jacoco/5IqM4AibmT8/-x5w4kU9BAAJ

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM