多模块应用的 Android 测试覆盖率报告

标签 android unit-testing automated-tests integration-testing android-espresso

我们有一个多模块应用程序。我们有 3 个图书馆项目和 1 个启动项目。

module1(图书馆) module2 (Libraray) 依赖于 module1 module3 (Libraray)依赖于module1

启动(没有任何源代码,它只是所有库的启动器)取决于模块 1 和模块 2。

在模块 1 中,我们使用外观模式访问模块 2 和模块 3 类。因此,我们需要在启动项目中编写所有测试用例,因为我们可以访问启动项目中的所有类,这样我们就可以访问所有类,并且测试用例不会因 NoClassDefException 而失败。

当我们在 Launch 项目中编写测试用例时,我们就能够运行测试用例,我们得到 100% 的执行报告,它会创建一个包含测试用例所有详细信息的 index.html 文件,但是当我尝试生成覆盖率报告然后它不显示覆盖率报告的任何数据。下面是我的 gradle 文件。

apply plugin: 'com.android.application'
apply plugin: 'jacoco'
android {
compileSdkVersion 22
buildToolsVersion "23.0.2"`

defaultConfig {
    applicationId "com.test.mobile"
    minSdkVersion 14
    targetSdkVersion 17
    multiDexEnabled true
    testApplicationId "com.test.mobile.test"
    testInstrumentationRunner 'android.support.test.runner.AndroidJUnitRunner'
}

repositories {
    mavenCentral()
}

buildTypes {

    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
    }

    debug{
        testCoverageEnabled true
    }
}


dexOptions {
    preDexLibraries = false
    javaMaxHeapSize "4096M"
    jumboMode = true
    incremental false
}

afterEvaluate {
    tasks.matching {
        it.name.startsWith('dex')
    }.each { dx ->
        if (dx.additionalParameters == null) {
            dx.additionalParameters = []
        }
        dx.additionalParameters += '--multi-dex'
        dx.additionalParameters += "--main-dex-list=$projectDir\\multidex-main-dex-list.txt".toString()
    }
}}
dependencies {
compile project(':module2')
compile project(':module3')
compile "com.android.support.test.espresso:espresso-idling-resource:2.2.1"

// Dependencies for local unit tests
testCompile "junit:junit:4.12" exclude group: 'com.android.support', module: 'support-annotations'

testCompile "org.mockito:mockito-all:1.10.19" exclude group: 'com.android.support', module: 'support-annotations'
testCompile "org.hamcrest:hamcrest-all:1.3" exclude group: 'com.android.support', module: 'support-annotations'
testCompile "org.powermock:powermock-module-junit4:1.6.2" exclude group: 'com.android.support', module: 'support-annotations'
testCompile "org.powermock:powermock-api-mockito:1.6.2" exclude group: 'com.android.support', module: 'support-annotations'


// Android Testing Support Library's runner and rules
androidTestCompile "com.android.support.test:runner:0.4.1"  exclude group: 'com.android.support', module: 'support-annotations'
androidTestCompile "com.android.support.test:rules:0.4.1" exclude group: 'com.android.support', module: 'support-annotations'

// Espresso UI Testing dependencies.
androidTestCompile "com.android.support.test.espresso:espresso-core:2.2.1" exclude group: 'com.google.code.findbugs' exclude group: 'javax.annotation' exclude group: 'com.android.support', module: 'support-annotations' exclude module: 'javax.annotation-api'
androidTestCompile "com.android.support.test.espresso:espresso-contrib:2.2.1" exclude group: 'com.google.code.findbugs' exclude group: 'javax.annotation' exclude group: 'com.android.support', module: 'support-annotations' exclude module: 'javax.annotation-api' exclude group: 'com.android.support', module: 'support-v4'
androidTestCompile "com.android.support.test.espresso:espresso-intents:2.2.1" exclude group: 'com.google.code.findbugs' exclude group: 'javax.annotation' exclude group: 'com.android.support', module: 'support-annotations' exclude module: 'javax.annotation-api'}

任务 jacocoTestReport(类型:JacocoReport,dependsOn:'testDebugUnitTest'){ def 项目 = new ArrayList() subprojects.each { prj -> 项目.add(prj) }

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

jacocoClasspath = configurations['androidJacocoAnt']

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])
/*sourceDirectories = generateSourceFiles(projects)
classDirectories = generateClassDirs(projects)*/

executionData = files(["${buildDir}/jacoco/testDebugUnitTest.exec",
                       "${buildDir}/outputs/code-coverage/connected/coverage.ec"
])}

最佳答案

我有 3 个名为 gcm_demo、googleservices 和 networkcommunication 的模块 所以在每个模块的build.gradle下 写

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"
])
} 

现在在 Project build.gradle 中编写以下 scrpit

apply plugin: 'jacoco'
task jacocoRootReport(type: JacocoReport, dependsOn: ['gcm_demo:jacocoTestReport', 'googleservice:jacocoTestReport', 'networkcommunication:jacocoTestReport']) {
reports {
    xml.enabled = true
    html.enabled = true
}
sourceDirectories = files([tasks.getByPath("gcm_demo:jacocoTestReport").sourceDirectories,
                           tasks.getByPath("googleservice:jacocoTestReport").sourceDirectories,
                           tasks.getByPath("networkcommunication:jacocoTestReport").sourceDirectories])

classDirectories = files([tasks.getByPath("gcm_demo:jacocoTestReport").classDirectories,
                          tasks.getByPath("googleservice:jacocoTestReport").classDirectories,
                          tasks.getByPath("networkcommunication:jacocoTestReport").classDirectories])

executionData = files([tasks.getByPath("gcm_demo:jacocoTestReport").executionData,
                       tasks.getByPath("googleservice:jacocoTestReport").executionData,
                       tasks.getByPath("networkcommunication:jacocoTestReport").executionData])

}

执行用

gradlew clean jRR (short abbreviation)

构建成功后输出文件夹为

{project location}\build\reports\jacoco\jacocoRootReport\html\index.html

它提供了 UI 和单元测试的完整项目覆盖

关于多模块应用的 Android 测试覆盖率报告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37693566/

相关文章:

android - 如何同时在多个设备上运行 android Instrument 测试

android - 如何从 fragment 切换到对话 fragment

java - 使用 @Test 注释在 Junit 测试中期望异常或其子类之一

java - 同时使用 Button 和 Tab?

unit-testing - Joe Armstrong 在 "there are more advanced techniques"中提到的单元测试是什么

android - 如何为通知进行android单元测试?

python - 应该测试 tdd 的静态文本,例如电子邮件主题?

testing - 在 TestCafe 中可以注册 xhr 并用作模拟(自动模拟)

android - 错误visual studio 2015 cordova Android包: extra-android-support

android - 在Android :的VideoView或MediaPlayer上方显示半透明覆盖