Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Android / Gradle - Jacoco gradle setup to join instrumentation and unit test coverage
// Merge of
// https://github.com/mgouline/android-samples/blob/master/jacoco/app/build.gradle
// and https://github.com/pushtorefresh/storio/blob/master/gradle/jacoco-android.gradle
// Requires Jacoco plugin in build classpath.
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.8.3"
}
// Enable test result in terminal
tasks.withType(Test) {
testLogging {
exceptionFormat "full"
events "skipped", "passed", "failed"
showStandardStreams true
}
jacoco.includeNoLocationClasses = true
}
variants().all { variant ->
def tag = "[
answers][jacoco.gradle]"
def variantName = variant.name
def variantCapName = variant.name.capitalize()
def fullTestTask = "testSuite${variantCapName}JacocoReport"
def unitTestTask = "test${variantCapName}UnitTest"
//
// use create<>CoverateReport since connectedCheck task does not generate jacoco reports so we
// need to depend on tasks that run tests + coverage
//
def instrumentedTestTask = "create${variantCapName}CoverageReport"
if (variantCapName == "Release") {
logger.info "$tag ${project.name} Task '$fullTestTask' is not enabled for Release builds."
return
}
if (project.tasks.findByName(unitTestTask) == null ||
project.tasks.findByName(instrumentedTestTask) ==
null) {
logger.warn "$tag ${project.name} Task '$fullTestTask' was not created, you can enable it by passing -PcoverageEnabled or by setting testCoverageEnabled=true in gradle.android setup."
return
}
task(fullTestTask, type: JacocoReport, dependsOn: [instrumentedTestTask, unitTestTask]) {
group = "Reporting"
description =
"Generate Jacoco coverage reports for $variantCapName Instrumented and UnitTest Tests"
onlyIf = { return true }
reports {
xml.enabled = true
html.enabled = true
csv.enabled = false
}
def androidFilter = ['**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/*$Lambda$*.*', // Jacoco can not handle several "$" in class name.
'**/*Module.*', // Modules for Dagger.
'**/*Dagger*.*', // Dagger auto-generated code.
'**/*MembersInjector*.*', // Dagger auto-generated code.
'**/*_Provide*Factory*.*',
'**/*_Factory.*', //Dagger auto-generated code
'**/*$*$*.*', // Anonymous classes generated by kotlin
//add libraries
'androidx/**/*.*',
'android/**/*.*',
//remove what we don't test
'androidTest/**/*.*',
'test/**/*.*',
'**/injector/**/*.*',
'**/model/**/*.*',
'**/mock/**/*.*',
'**/event/**/*.*',
'**/**_ViewBinding**',
'**/*EventType.*',
'**/**Mocked']
def librariesFilter = ['**/com/esotericsoftware/**/*.*',
'**/com/crashlytics/**/*.*',
'**/com/facebook/**/*.*',
'**/com/jakewharton/**/*.*',
'**/com/onesignal/**/*.*',
'**/com/viewpagerindicator/**/*.*',
'**/io/fabric/**/*.*',
'**/io/reactivex/**/*.*',
'**/net/danlew/**/*.*',
'**/timber/**/*.*',
'**/removeme/**/*.*',
'**/squareup/**/*.*',]
def fileFilter = androidFilter + librariesFilter
def classTree = fileTree(dir: variant.javaCompiler.destinationDir, excludes: fileFilter) +
fileTree(dir: "$buildDir/tmp/kotlin-classes/$variantName", excludes: fileFilter)
sourceDirectories = files(["src/main/java",
"src/main/kotlin",
"src/$variantName/java",
"src/$variantName/kotlin"])
classDirectories = files([classTree])
executionData = fileTree(dir: "$buildDir",
includes: ["jacoco/test${variantCapName}UnitTest.exec",
"outputs/code_coverage/debugAndroidTest/connected/*coverage.ec"])
doLast {
println "Custom $fullTestTask Jacoco task run for instrumented and unit-tests."
}
}
}
def variants() {
if (project.android.hasProperty('libraryVariants')) {
return project.android.libraryVariants
} else {
return project.android.applicationVariants
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment