Skip to content

ChristopherBull/demo-merge-android-coverage

Repository files navigation

Demo: Merging Android test coverage reports

Build Status Test Coverage Maintainability

Example repository demonstrating combining Android unit and instrumented test coverage reports using JaCoCo. It features:

  • Combining Unit test coverage and Instrumented (emulator) test coverage reports.
  • Supports Java, Kotlin, and Java+Kotlin projects.
  • Supports usage in CI/CD workflows and pipelines.

Code Coverage

Android Studio has built-in code coverage support, but coverage is only reported for Instrumented Tests, not Unit tests (or both combined). Further, external services that may combine reports for you (e.g., as part of your CI/CD workflow) prevent your from calculating full coverage reports locally, offline, internal to any CI workflows, and may have service costs associated with them.

This is where this solution comes in.

Usage

Run in a terminal (Linux, Mac, etc):

$ ./gradlew jacocoCombinedTestReports

Run in a terminal (Windows):

> gradlew jacocoCombinedTestReports

The generated HTML (and XML) reports will be located under: app/build/reports/coverage/jacocoCombinedTestReports/. Note that app/ is the default module name/directory, so the above path will work unless you have configured your projects to use a different module name (or have multiple modules).

An example usage in a CI workflow using GitHub Actions is also available in this repository, which uploads generated HTML as artifacts and uploads the combined JaCoCo xml report to a third-party service (demonstrated by the "test coverage" percentage badge at the top of this file).

Configuration

The following build.gradle snippets should be merged into your existing build.gradle files (not replacing them). Complete minimal working examples are available within this repository.

In the project-level build.gradle file:

buildscript {
    ext.jacocoVersion = '0.8.7'
    dependencies {
        classpath "org.jacoco:org.jacoco.core:$jacocoVersion"
    }
}

In your module-level build.gradle file (e.g., /app/build.gradle):

apply plugin: 'jacoco'

jacoco {
    toolVersion = "$jacocoVersion"
    reportsDirectory = file("$buildDir/reports/coverage")
}

tasks.withType(Test) {
    jacoco.includeNoLocationClasses = true
    jacoco.excludes = ['jdk.internal.*']
}

task jacocoCombinedTestReports(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'createDebugCoverageReport']) {
    group = "Verification"
    description = "Creates JaCoCo test coverage report for Unit and Instrumented Tests (combined) on the Debug build"
    reports {
        xml.enabled = true
        html.enabled = true
    }

    // Files to exclude:
    // Generated classes, platform classes, etc.
    def excludes = [
            '**/R.class',
            '**/R$*.class',
            '**/BuildConfig.*',
            '**/Manifest*.*',
            '**/*Test*.*',
            'android/**/*.*'
    ]

    // generated classes
    classDirectories.from = fileTree(
            dir: "$buildDir/intermediates/classes/debug",
            excludes: excludes
    ) + fileTree(
            dir: "$buildDir/tmp/kotlin-classes/debug",
            excludes: excludes
    )
    // sources
    sourceDirectories.from = [
            android.sourceSets.main.java.srcDirs,
            "src/main/kotlin"
    ]
    // Output and existing data
    // Combine Unit test and Instrumented test reports
    executionData.from = fileTree(dir: "$buildDir", includes: [
            // Unit tests coverage data
            "outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec",
            // Instrumented tests coverage data
            "outputs/code_coverage/debugAndroidTest/connected/*coverage.ec"
    ])
}

android {
    buildTypes {
        debug {
            testCoverageEnabled true
        }
    }
}

That's it, you are all set.

About

Example repository demonstrating combining Android unit and instrumented test coverage reports using JaCoCo.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages