【问题标题】:Jacoco Coverage Report issuesJacoco 覆盖报告问题
【发布时间】:2016-05-14 03:17:07
【问题描述】:

我正在尝试定义位置,jacoco 将为在真实设备上运行的仪器测试创建覆盖文件。

从 gradle 任务的--debug 运行中,我看到了这个日志:

[DEBUG] [org.gradle.api.Task] DeviceConnector 'Nexus 5X - 6.0.1': installing /home/martin/workspace/lib/my-lib/build/outputs/apk/my-lib-debug-androidTest-unaligned.apk
[INFO] [org.gradle.api.Task] Starting 1 tests on Nexus 5X - 6.0.1
[INFO] [org.gradle.api.Task]  de.my.lib.utils.UtilsTest testMyTest[Nexus 5X - 6.0.1] [32mSUCCESS [0m
[DEBUG] [org.gradle.api.Task] DeviceConnector 'Nexus 5X - 6.0.1': fetching coverage data from /data/data/de.my.lib.test/coverage.ec
[DEBUG] [org.gradle.api.Task] DeviceConnector 'Nexus 5X - 6.0.1': uninstalling de.my.lib.test 13:46:14.538
[DEBUG] [org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter] Finished executing task ':my-lib:connectedDebugAndroidTest'

我尝试了 3 种方法来定义位置:

在清单文件中使用<instrumentation> 标记并没有改变任何东西。

<?xml version="1.0" encoding="utf-8"?>
<manifest
    package="de.my.lib.test"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <instrumentation
        android:name="android.support.test.runner.AndroidJUnitRunner"
        xmlns:tools="http://schemas.android.com/tools"
        android:targetPackage="de.my.lib.test"
        tools:replace="android:targetPackage">
        <meta-data
            android:name="coverage"
            android:value="true" />
        <meta-data
            android:name="coverageFile"
            android:value="/sdcard/coverage.ec" />
    </instrumentation>
</manifest>

我用 gradle 试过了,但输出是一样的:

defaultConfig {
    // unimportant stuff
    testApplicationId "de.my.lib.test"

    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    testInstrumentationRunnerArgument('coverageFile', '/sdcard/coverage.ec')
}

最后我用adb命令试了一下:

adb shell am instrument -w -e coverage true -e coverageFile /sdcard/coverage.ec de.my.lib.test/android.support.test.runner.AndroidJUnitRunner

但我得到 2 个错误:

de.my.lib.utils.UtilsTest:. 找不到类:org.jacoco.agent.rt.internal_773e439.CoverageTransformer . 时间:0,072

正常(1 次测试)

错误:无法生成 emma 覆盖率。

我在这里完全迷失了。有什么想法吗?

背景 为什么我需要将其存储在另一个地方:在某些设备和 Android 版本上存在adb shell run-as 命令的错误,因此我的测试设备场中有设备返回 0 % 覆盖率,因为无法拉取文件。所以我需要将文件存储在一个公开的位置。

【问题讨论】:

    标签: android gradle code-coverage jacoco test-coverage


    【解决方案1】:

    但是,尚未生成覆盖率报告。要启用此选项,我们需要向我们的调试构建变体添加一个属性。使用 Android 插件 DSL,我们可以通过 testCoverageEnabled 属性启用覆盖:

    android {
        ...
        buildTypes {
            debug {
                testCoverageEnabled true
            }
            ...
        }
    }
    

    要在使用 Android Gradle 插件版本 2.2.+ 时启用本地测试的覆盖率报告,您需要在应用的build.gradle 中启用它:

    android {
        //...
    
        testOptions {
            unitTests.all {
                jacoco {
                    includeNoLocationClasses = true
                }
            }
        }
    }
    

    Jacoco 执行的instrumentation 生成执行文件,其中包含创建报告所需的数据(HTML、XML 等)。这里的问题是,Espresso 生成.ec 文件,而单元测试执行生成.exec 文件……我们有不同的格式!

    由于我们无法配置 Espresso 的覆盖任务,我们必须确保它首先被执行。接下来,我们需要运行单元测试,然后使用两个文件(ecexec)创建覆盖率数据。

    要启用此功能,我们需要再次编辑任务并将coverage.ec 文件作为参数添加到executionData 属性中:

    apply plugin: 'jacoco'
    
    task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'createDebugCoverageReport']) {
    
        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"
    
        sourceDirectories = files([mainSrc])
        classDirectories = files([debugTree])
        executionData = fileTree(dir: "$buildDir", includes: [
                "jacoco/testDebugUnitTest.exec", 
                "outputs/code-coverage/connected/*coverage.ec"
        ])
    }
    

    由于 Android Gradle 插件 2.2.+ 现在为每次执行生成一个覆盖文件,使用文件名中的设备/模拟器,现在我们需要将每个文件传递给执行数据,因为文件名现在是动态的。另外,我添加了createDebugCoverageReport任务作为我们自定义任务的依赖,所以我们不需要手动运行它:)

    最后,当我们执行这两个任务时,首先运行 Espresso 测试,我们将得到统一的覆盖率报告!

    gradle clean jacocoTestReport
    

    详细解释见here

    编辑:

    因此,adb shell am instrument 命令不会生成报告,为此您必须使用 gradle 解决方案来处理它。如果你真的想自己测试,那么你必须使用custom runner

    参考资料:

    1) How to Generate Android Testing Report in HTML Automatically

    2)How to retrieve test results when using "adb shell am instrument"

    3)https://github.com/jsankey/android-junit-report


    Test from the command line


    按照these的步骤更新为命令行方法。

    运行检测的应用程序

    一旦我们有了EmmaInstrumentation 类(在参考链接中),我们需要进行更多调整才能获得正在运行的应用程序的覆盖率报告。

    首先,我们需要将新的 Activity 添加到清单中。其次,如果我们决定生成覆盖率报告,我们应该允许我们的应用程序写入 sdcard。为此,您应该授予 android.permission.WRITE_EXTERNAL_STORAGE 权限。 然后,是时候构建和安装检测的 apk:

    $ ant clean
    $ ant instrument
    $ ant installi
    

    一切准备就绪,开始检测应用程序

    $ adb shell am instrument -e coverage true \
        -w com.example.i2at.tc/\
            com.example.instrumentation.EmmaInstrumentation
    

    Here 是源代码。

    【讨论】:

    • 不是 gradle 方式,而是来自 "adb shell am instrument..."
    • 想法是通过命令行获取它,因为我们正在测试系统应用程序。它使用 mk 文件生成与一般方式不同的构建,即使用 gradle 脚本。
    • @TheLittleNaruto 我已经更新了我的答案,如果对你有帮助,请查看。
    • 感谢您付出太多努力。但是我们没有使用蚂蚁。还有你提到的我们已经尝试过了。
    • 我找到了根本原因。发布了答案。检查一次。
    【解决方案2】:

    缺少的CoverageTransformer 类提示缺少对 JaCoCo 代理运行时的依赖。一种简单的解决方案可能是,为它提供所需的东西(在设备上可用):

    testImplementation "org.jacoco:org.jacoco.agent:0.8.3"
    

    如果你得到一个FileNotFoundException,当ClassNotFoundException被修复时,确保有写入SD卡的权限,这似乎是另一个可能的陷阱:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    

    正如我刚刚看到的,还有一个org.jacoco.report 包,可以随意添加:

    testImplementation "org.jacoco:org.jacoco.report:0.8.3"
    

    org.jacoco.agent在任何情况下都是包含类CoverageTransformer的包。

    【讨论】:

      【解决方案3】:

      对我们来说,它是一款 AOSP 应用。我们在禁用 Jack 编译器的情况下生成测试和模块 apk,这导致了这个进一步的问题。因为我们需要 Jack 编译器来生成 coverage.em。但这个错误不太相关。所以没有进一步的线索。

      所以解决方法是运行 jack 编译器服务器并获取使用它生成的 apk。

      【讨论】:

      • 这个答案与问题中的错误信息有什么关系?没有关于 coverage.em 没有找到,但是 CoverageTransformer 没有找到。
      • 再次阅读答案。 @MartinZeitler 错误与问题相同。
      • @TheLittleNaruto 我检查您的答案是关于在应用程序发布之后,而在问题中没有提到那件事;它只是关于调试应用程序的说法,所以我的回答是基于那件事。顺便说一句,我感到很高兴;你解决了你的问题。
      猜你喜欢
      • 2018-09-09
      • 2015-08-03
      • 1970-01-01
      • 2017-01-03
      • 1970-01-01
      • 1970-01-01
      • 2022-06-15
      • 2018-07-27
      • 1970-01-01
      相关资源
      最近更新 更多