apply plugin: 'jacoco' jacoco { toolVersion = "0.8.10" } 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" 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/**/*.*', // butterKnife '**/*$ViewInjector*.*', '**/*$ViewBinder*.*', '**/*ViewBinding*.*', // dagger '**/*_MembersInjector.class', '**/Dagger*Component.class', '**/Dagger*Component$Builder.class', '**/*Module_*Factory.class', '**/di/*', '**/*_Factory*.*', '**/*Module*.*', '**/*Dagger*.*', '**/*Hilt*.*', // 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$*.*', // model '**/**/model/*', '**/**/models/*', '**/model/*', // concurrency '**/concurrency/*', // kvstore '**/kvstore/*', // db '**/db/*', // data '**/data/*', // zoom controllers are part of external library '**/**/zoomControllers/*', ] tasks.create(name: "${unitTestTask}UnifiedCoverage", type: JacocoReport, dependsOn: [ "$unitTestTask", "$androidTestCoverageTask", ]) { group = "Reporting" description = "Generate Jacoco unified coverage reports for the ${variantName.capitalize()} build" reports { html { enabled true } xml { enabled true } } 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 ])) } tasks.create(name: "${unitTestTask}Coverage", type: JacocoReport, dependsOn: [ "$unitTestTask" ]) { group = "Reporting" description = "Generate Jacoco coverage reports for the ${variantName.capitalize()} build" reports { html { enabled true } xml { enabled true } } 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)) executionData(files([ "$project.buildDir/jacoco/${unitTestTask}.exec" ])) } } }