当前位置: 首页 > 知识库问答 >
问题:

Powermock Jacoco Gradle 0%的Android项目覆盖率

通京
2023-03-14

我们有一个Android项目,我们使用Powermock进行一些测试用例,使用Jacoco进行覆盖率报告。我们注意到,我们的一些类返回0%覆盖率,尽管它们确实被覆盖。我们还观察了下面关于受影响类的消息。

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

一些在线搜索显示Powermock和Jacoco玩得不好,离线仪器是一种可能的解决方法。

之前有人使用过android项目的gradle离线插装脚本吗?

共有1个答案

钮边浩
2023-03-14

事后看来,我想这可以通过足够的android经验和在线阅读来解决。然而,当它落在我腿上时,我对Android、gradle和groovy相对较新,所以我正在为下一个我写这篇文章:-D

简而言之,正在发生的事情(摘自雅各布论坛)

    < li >源文件被编译成未检测的类文件 < li >对未检测的类文件进行检测(离线预检测,或在运行时由Java代理自动检测) < li >执行收集到exec文件中的插入指令的类 < li >报告用从exec文件和原始未插入指令的类文件的分析中获得的信息来修饰源文件 < li >消息“<代码>类...与执行数据不匹配。”表示用于生成报告的类文件与检测之前的类不同。

解决方案

Jacoco脱机检测页面提供了本摘录中脱机检测应执行的主要步骤:

对于这种情况,类文件可以使用 JaCoCo 进行预检测,例如使用仪器 Ant 任务。在运行时,预检测的类需要位于类路径上,而不是原始类上。此外,必须将.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 {
        html" target="_blank">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

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

    在命令行运行:gradle清理

    gradle清洁将清除任何先前的gradle执行工件

    <code>gradle createOfflineTestCoverageReport

    gradle jaco测试报告将运行测试并生成基于以前生成的.exec文件的计算机报告

    感到失落吗?

    我已经将一个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
    

  •  类似资料:
    • 我有这样的项目结构: 模块应用程序 模块-登录 模块注册 问题:我有上面喜欢Android项目的结构,能够生成jaco代码覆盖率报告,并且可以用于声纳仪表板。我面临的espresso测试问题,它只显示模块应用程序的代码覆盖率,而不显示其他模块的代码覆盖率。Espresso测试正在运行用例流,如注册,然后从其他两个模块登录和调用类,但其他两个模块的覆盖率始终为0%。 < li >我想了解espres

    • 问题内容: 似乎有几个问题,这些问题已经很老了,并且从Java 8对Jacoco的支持开始发生了变化。 我的项目包含以下结构 我已经配置了这样的 主POM.xml Pom.xml B pom.xml 我正在执行此命令。我可以看到jacoco.exec正在生成,但是我看不到任何HTML报告正在验证数据。 请帮我解决一下这个。还有一点是,我的配置对项目是否正确? 更新资料 已确定的问题。 变成 现在,

    • 我正在设置通过SonarQube服务器分析项目。使用的工具集是: Kotlin 1.3.61 Gradle 6.0.1 Jacoco 0.7.9 SonarQube 7.5 SonnarQube Gradle插件2.7 问题是,我在SonarQube中有0.0%的覆盖率,但同时我有一份格式良好的jacoco测试覆盖率报告。以下是中的片段: 在执行< code >期间,我有下一个日志条目。/grad

    • 问题内容: 我们正在使用Android库项目在Android应用程序的不同内部版本(目标)之间共享核心类和资源。每个特定目标的Android项目都引用Core库项目(在幕后,Eclipse会从引用的库项目中创建并引用一个jar)。 覆盖资源(例如图像和XML布局)很容易。构建应用程序时,放置在目标项目中的资源文件(例如应用程序图标或XML布局)会自动覆盖具有相同名称的核心库资源。但是,有时需要重写

    • 我试图获得基于gradle的android项目的覆盖面。 所以我为我的应用程序添加版本。gradle 和 内部调试。 这工作正常。我可以获取使用或的报告。 问题是调试版本通常被开发人员用来运行和测试应用程序。因此,在构建中启用代码覆盖可能会降低构建的速度,这种用法可能不需要。 所以我想我会添加新的配置 不幸的是,没有和不运行覆盖类型。 当我使用dex2jar反编译apk并使用jd-gui查看内部时

    • 我正在运行我的selenium项目模块,它不是主项目的一部分,我用Jacoco maven插件和surefire插件运行selenium测试,Jacoco只给出了selenium项目的代码覆盖(exec文件),而不是整个项目...我需要如何配置我的Jacoco和Surefire以获得外部/整个项目覆盖??