Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jacoco code coverage 0% in Android-kotlin project

I have been trying to implement Jacoco for code coverage in Android kotlin project. I used deafult android studio coverage tool but it was not reliable. So I tried to implement Jacoco but I am getting 0% code coverage even after tests are passing successfully.

0% Coverage -

enter image description here

Succesfull test run -

enter image description here

Here is the gradle script -

plugins {
id 'com.android.library'
id 'kotlin-android'
id 'jacoco'
}


android {
compileSdkVersion 30
buildToolsVersion "30.0.3"

defaultConfig {
    minSdkVersion 21
    targetSdkVersion 30
    versionCode 1
    versionName "1.0"

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles "consumer-rules.pro"
}

buildTypes {
    debug {
        debuggable true
        minifyEnabled false
        testCoverageEnabled true
    }
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}
compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
    jvmTarget = '1.8'
}
testOptions {
    unitTests.returnDefaultValues = true
}

}



dependencies {

implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.5.0'
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'com.google.android.material:material:1.3.0'
testImplementation 'junit:junit:4.+'
testImplementation 'org.mockito:mockito-core:3.11.2'

testImplementation 'org.mockito:mockito-inline:3.11.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

jacoco {
toolVersion = "0.8.5"
// Custom reports directory can be specfied like this:
// reportsDir = file("$buildDir/customJacocoReportDir")
}

tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
jacoco.excludes = ['jdk.internal.*']
// see related issue https://github.com/gradle/gradle/issues/5184#issuecomment-457865951
}

project.afterEvaluate {

(android.hasProperty('applicationVariants')
        ? android.'applicationVariants'
        : android.'libraryVariants')
        .all { variant ->
            def variantName = variant.name
            def unitTestTask = "test${variantName.capitalize()}UnitTest"
            def androidTestCoverageTask = "create${variantName.capitalize()}CoverageReport"

            tasks.create(name: "${unitTestTask}Coverage", type: JacocoReport, dependsOn: [
                    "$unitTestTask",
                    "$androidTestCoverageTask"
            ]) {
                group = "Reporting"
                description = "Generate Jacoco coverage reports for the ${variantName.capitalize()} build"

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

                def excludes = [
                        // data binding
                        'android/databinding/**/*.class',
                        '**/android/databinding/*Binding.class',
                        '**/android/databinding/*',
                        '**/androidx/databinding/*',
                        '**/BR.*',
                        // android
                        '**/R.class',
                        '**/R$*.class',
                        '**/BuildConfig.*',
                        '**/Manifest*.*',
                        '**/*Test*.*',
                        'android/**/*.*',
                        // kotlin
                        '**/*MapperImpl*.*',
                        '**/*$ViewInjector*.*',
                        '**/*$ViewBinder*.*',
                        '**/BuildConfig.*',
                        '**/*Component*.*',
                        '**/*BR*.*',
                        '**/Manifest*.*',
                        '**/*$Lambda$*.*',
                        '**/*Companion*.*',
                        '**/*Module*.*',
                        '**/*Dagger*.*',
                        '**/*Hilt*.*',
                        '**/*MembersInjector*.*',
                        '**/*_MembersInjector.class',
                        '**/*_Factory*.*',
                        '**/*_Provide*Factory*.*',
                        '**/*Extensions*.*',
                        // sealed and data classes
                        '**/*$Result.*',
                        '**/*$Result$*.*'
                ]

                def javaClasses = fileTree(dir: variant.javaCompileProvider.get().destinationDir,
                        excludes: excludes)
                def kotlinClasses = fileTree(dir: "${buildDir}/tmp/kotlin-classes/${variantName}",
                        excludes: excludes)

                classDirectories.setFrom(files([
                        javaClasses,
                        kotlinClasses
                ]))

                def variantSourceSets = variant.sourceSets.java.srcDirs.collect { it.path }.flatten()
                sourceDirectories.setFrom(project.files(variantSourceSets))

                def androidTestsData = fileTree(dir: "${buildDir}/outputs/code_coverage/${variantName}AndroidTest/connected/", includes: ["**/*.ec"])

                executionData(files([
                        "$project.buildDir/jacoco/${unitTestTask}.exec",
                        androidTestsData
                ]))
            }

        }
}
like image 533
riskPlayGround Avatar asked Jun 30 '21 12:06

riskPlayGround


1 Answers

Right now, for an android multimodule project with:

  • jacoco 0.8.7
  • gradle plugin 7.0.2

I am finding that if debug { testCoverageEnabled true } is set, jacoco produces no output for unit tests (eg testDebugUnitTest). Whereas if it is not, /build/jacoco/testDebugUnitTest.exec is created, with actual coverage data.

This is clearly a bug, but not sure what component it's in. It is bad because it means that it'll work for either device or unit tests, but not both at the same time.

like image 178
Sofi Software LLC Avatar answered Sep 18 '22 20:09

Sofi Software LLC