Skip to content

Instantly share code, notes, and snippets.

@xdtianyu
Forked from bhargavms/jacoco.gradle
Created August 21, 2018 07:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xdtianyu/0be1fd138e52000d5c462306dacff176 to your computer and use it in GitHub Desktop.
Save xdtianyu/0be1fd138e52000d5c462306dacff176 to your computer and use it in GitHub Desktop.
A gradle plugin for checking test coverage using jacoco.
apply plugin: 'jacoco'
jacoco {
toolVersion "0.7.1.201405082137"
reportsDir = file("$buildDir/intermediates/test")
}
// Taken from https://blog.gouline.net/2015/06/23/code-coverage-on-android-with-jacoco/
project.afterEvaluate {
// Grab all build types and product flavors
def buildTypes = android.buildTypes.collect { type -> type.name }
def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
// When no product flavors defined, use empty
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
def sourceName, sourcePath
if (!productFlavorName) {
sourceName = sourcePath = "${buildTypeName}"
} else {
sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
sourcePath = "${productFlavorName}/${buildTypeName}"
}
def testTaskName = "test${sourceName.capitalize()}UnitTest"
// Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest'
task "${testTaskName}Coverage" (type:JacocoReport, dependsOn: "$testTaskName") {
group = "Reporting"
description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
classDirectories = fileTree(
dir: "${project.buildDir}/intermediates/classes/${sourcePath}",
excludes: ['**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/Manifest*.*',
'android/**']
)
logger.lifecycle("Class directories = ${classDirectories.dir}")
def coverageSourceDirs = [
"src/main/java",
"src/$productFlavorName/java",
"src/$buildTypeName/java"
]
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
reports {
xml.enabled = true
html.enabled = true
}
}
ext {
limits = [
'instruction': 1,
'branch' : 0,
'line' : 1,
'complexity' : 0,
'method' : 0.5,
'class' : 1
]
}
task("check${testTaskName}Coverage", dependsOn: "${testTaskName}Coverage") {
doLast {
def report = file("$buildDir/intermediates/test/${testTaskName}Coverage/${testTaskName}Coverage.xml")
logger.lifecycle("Checking coverage results: ${report}")
def parser = new XmlParser()
parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false)
def results = parser.parse(report)
def percentage = {
def covered = it.'@covered' as Double
def missed = it.'@missed' as Double
((covered / (covered + missed)) * 100).round(2)
}
def counters = results.counter
def metrics = [:]
metrics << [
'instruction': percentage(counters.find { it.'@type'.equals('INSTRUCTION') }),
'branch' : percentage(counters.find { it.'@type'.equals('BRANCH') }),
'line' : percentage(counters.find { it.'@type'.equals('LINE') }),
'complexity' : percentage(counters.find { it.'@type'.equals('COMPLEXITY') }),
'method' : percentage(counters.find { it.'@type'.equals('METHOD') }),
'class' : percentage(counters.find { it.'@type'.equals('CLASS') })
]
def failures = []
def coverages = []
metrics.each {
coverages.add("- ${it.key} coverage rate is: ${it.value}%")
def limit = limits[it.key]
if (it.value < limit) {
failures.add("- ${it.key} coverage rate is: ${it.value}%, minimum is ${limit}%")
}
}
if (failures) {
logger.quiet("------------------ Code Coverage Failed -----------------------")
failures.each {
logger.quiet(it)
}
logger.quiet("---------------------------------------------------------------")
throw new GradleException("Code coverage failed")
} else {
coverages.each {
logger.quiet(it)
}
logger.quiet("Passed Code Coverage Checks")
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment