Filter JaCoCo coverage reports with Gradle
JavaUnit TestingGradleCode CoverageJacocoJava Problem Overview
Problem:
I have a project with [tag:JaCoCo] and I want to be able to filter certain classes and/or packages.
Related Documentation:
I have read the following documentation:
Official [tag:JaCoCo] site: http://www.eclemma.org/jacoco/index.html
Official [tag:JaCoCo] docs for [tag:Gradle]: https://gradle.org/docs/current/userguide/jacoco_plugin.html
Official [tag:JaCoCo] Github
issues, working on coverage:
https://github.com/jacoco/jacoco/wiki/FilteringOptions
https://github.com/jacoco/jacoco/issues/14
Related StackOverflow Links:
https://stackoverflow.com/questions/19625640/jacoco-gradle-filtering-options (No answer)
https://stackoverflow.com/questions/27033757/exclude-packages-from-jacoco-report-using-sonarrunner-and-gradle (Not using [tag:sonar])
https://stackoverflow.com/questions/14682389/jacoco-exclude-jsp-from-report (It seems to work for [tag:maven], I am using [tag:gradle])
https://stackoverflow.com/questions/27799419/maven-jacoco-configuration-exclude-classes-packages-from-report-not-working (It seems to work for [tag:maven], I am using [tag:gradle])
https://stackoverflow.com/questions/23756014/jacoco-gradle-plugin-exclude (Could not get this to work)
https://stackoverflow.com/questions/17394427/gradle-jacoco-coverage-reports-includes-classes-excluded-in-configuration (Seems very close, it used doFirst
, did not work for me)
Example of what I have tried:
apply plugin: 'java'
apply plugin: 'jacoco'
buildscript {
repositories {
mavenCentral()
jcenter()
}
}
repositories {
jcenter()
}
jacocoTestReport {
reports {
xml {
enabled true // coveralls plugin depends on xml format report
}
html {
enabled true
}
}
test {
jacoco {
destinationFile = file("$buildDir/jacoco/jacocoTest.exec")
classDumpFile = file("$buildDir/jacoco/classpathdumps")
excludes = ["projecteuler/**"] // <-- does not work
// excludes = ["projecteuler"]
}
}
}
Question:
How can I exclude certain packages and classes when generating the [tag:JaCoCo] coverage reports?
Java Solutions
Solution 1 - Java
Yannick Welsch
:
Thanks to, After searching Google, reading the Gradle docs and going through older StackOverflow posts, I found this answer on the Official [tag:Gradle] forums!
jacocoTestReport {
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: 'com/blah/**')
}))
}
}
Source: https://issues.gradle.org/browse/GRADLE-2955
For older gradle versions < 5.x may need to use
classDirectories = files(classDirectories.files.collect {
instead of classDirectories.setFrom
build.gradle
for Java/Groovy projects:
Solution to my apply plugin: 'java'
apply plugin: 'jacoco'
jacocoTestReport {
reports {
xml {
enabled true // coveralls plugin depends on xml format report
}
html {
enabled true
}
}
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it,
exclude: ['codeeval/**',
'crackingthecode/part3knowledgebased/**',
'**/Chapter7ObjectOrientedDesign**',
'**/Chapter11Testing**',
'**/Chapter12SystemDesignAndMemoryLimits**',
'projecteuler/**'])
})
}
}
As you can see, I was successfully able to add more to exclude:
in order to filter a few packages.
Source: https://github.com/jaredsburrows/CS-Interview-Questions/blob/master/build.gradle
Custom tasks for other projects such as Android:
apply plugin: 'jacoco'
task jacocoReport(type: JacocoReport) {
reports {
xml {
enabled true // coveralls plugin depends on xml format report
}
html {
enabled true
}
}
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it,
exclude: ['codeeval/**',
'crackingthecode/part3knowledgebased/**',
'**/Chapter7ObjectOrientedDesign**',
'**/Chapter11Testing**',
'**/Chapter12SystemDesignAndMemoryLimits**',
'projecteuler/**'])
})
}
}
Solution 2 - Java
For Gradle version 5.x, the classDirectories = files(...)
gives a deprecation warning and does not work at all starting from Gradle 6.0
This is the nondeprecated way of excluding classes:
jacocoTestReport {
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: 'com/exclude/**')
}))
}
}
Solution 3 - Java
for me, it's fine working with
test {
jacoco {
excludes += ['codeeval/**',
'crackingthecode/part3knowledgebased/**',
'**/Chapter7ObjectOrientedDesign**',
'**/Chapter11Testing**',
'**/Chapter12SystemDesignAndMemoryLimits**',
'projecteuler/**']
}
}
as stated out in documentation https://docs.gradle.org/current/userguide/jacoco_plugin.html#N16E62 and initally asked so the answer is:
so if you ask me: it's not a question of
excludes = ["projecteuler/**"]
or
excludes += ["projecteuler/**"]
but
excludes = ["**/projecteuler/**"]
to exclude a package *.projecteuler.*
and test {}
on project level, not nested in jacocoTestReport
Solution 4 - Java
For Gradle6
Use something like below, because they made classDirectories as final
, we cannot re-assign it, but a setter method exists classDirectories.setFrom
which can be utilized
jacocoTestReport {
reports {
xml.enabled true
html.enabled true
html.destination file("$buildDir/reports/jacoco")
}
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it,
exclude: ['**/server/**',
'**/model/**',
'**/command/**'
]
)
}))
}
}
Solution 5 - Java
In order to filter in jacoco report, exclusion need to be done in two task jacocoTestReport
and jacocoTestCoverageVerification
.
sample code
def jacocoExclude = ['**/example/**', '**/*Module*.class']
jacocoTestReport {
afterEvaluate {
getClassDirectories().setFrom(classDirectories.files.collect {
fileTree(dir: it, exclude: jacocoExclude)
})
}
}
jacocoTestCoverageVerification {
afterEvaluate {
getClassDirectories().setFrom(classDirectories.files.collect {
fileTree(dir: it, exclude: jacocoExclude)
})
}
...
}
Solution 6 - Java
Here is a solution for this problem in ANT. This can be adapted to gradle by adding the following under the jacocoTestReport
task. Although this isn't really documented by jacoco, it seems like the only way to filter the test results for now.
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it, exclude: 'excluded/files/**')
})
}
Solution 7 - Java
for Kotlin users, here is what I used (gradle 6.7)
build.gradle.kts
tasks.jacocoTestReport {
// tests are required to run before generating the report
dependsOn(tasks.test)
// print the report url for easier access
doLast {
println("file://${project.rootDir}/build/reports/jacoco/test/html/index.html")
}
classDirectories.setFrom(
files(classDirectories.files.map {
fileTree(it) {
exclude("**/generated/**", "**/other-excluded/**")
}
})
)
}
as suggested here : https://github.com/gradle/kotlin-dsl-samples/issues/1176#issuecomment-610643709
Solution 8 - Java
This has been out for a while, but I just ran across this. I was struggling with all the exclusions needed. I found it was something much more simple for me. If you follow the Maven project layout style /src/main/java and /src/test/java, you simply need to put buildDir/classes/main in your classDirectories config like so:
afterEvaluate {
jacocoTestReport {
def coverageSourceDirs = ['src/main/java']
reports {
xml.enabled false
csv.enabled false
html.destination "${buildDir}/reports/jacocoHtml"
}
sourceDirectories = files(coverageSourceDirs)
classDirectories = fileTree(
dir: "${project.buildDir}/classes/main",
excludes: [
//whatever here like JavaConfig etc. in /src/main/java
]
)
}
}
Solution 9 - Java
The code below excludes classes from coverage verification as well:
jacocoTestCoverageVerification {
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: "${project.buildDir}/classes/main",
exclude: ['**/packagename/**'])
})
}
}
Solution 10 - Java
For those who still scratching their heads to filter certain packages from the coverage report, here is the configuration that works for me using the most recent libraries.
Build tool: Gradle 6.5 (also tried for 6.7)
Coverage Tool: Jacoco 0.8.5
Things to consider/Justifications
afterScript
is not required- Need to exclude it twice, one for report generation and coverage verification
- The intellij IDE recommends to use
excludes
param instead ofexclude
. Either of which just works fine - While providing the regex, be sure to provide the
.class
files and not the.java
files. - Post Gradle 5,
classDirectories
is a read-only field, therefore, useclassDirectories.setFrom
jacocoTestReport {
doLast {
println("See report file://${project.rootDir}/build/reports/jacoco/test/html/index.html")
}
excludedClassFilesForReport(classDirectories)
}
jacocoTestCoverageVerification {
excludedClassFilesForReport(classDirectories)
violationRules {
rule {
limit {
minimum = 0.55
}
}
}
}
private excludedClassFilesForReport(classDirectories) {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: [
'**/common/apigateway/*.class',a
'**/common/*/client/*Client*.class',
'**/configuration/*ClientConfiguration.class',
'**/model/search/*SearchService.class'
])
}))
}
check.dependsOn jacocoTestCoverageVerification
Solution 11 - Java
For anyone going out of their mind looking for this answer in Kotlin DSL, here it is:
val jacocoExclude = listOf("**/entities/**", "**/dtos/**")
jacocoTestReport {
reports {
xml.isEnabled = true
csv.isEnabled = false
}
classDirectories.setFrom(classDirectories.files.map {
fileTree(it).matching {
exclude(jacocoExclude)
}
})
}
test {
useJUnitPlatform()
systemProperty("gradle.build.dir", project.buildDir)
finalizedBy(jacocoTestReport)
extensions.configure(JacocoTaskExtension::class) {
excludes = jacocoExclude
}
}
Solution 12 - Java
For me, i have to do exclude in 2 places
jacocoTestReport {
dependsOn test // tests are required to run before generating the report
afterEvaluate {
excludedClassFilesForReport(classDirectories)
}
}
jacocoTestCoverageVerification {
afterEvaluate {
excludedClassFilesForReport(classDirectories)
}
}
private excludedClassFilesForReport(classDirectories) {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it,
exclude: [
'com/test/a/config/**',
'com/test/b/constant/**',
'com/test/c/MainApp.class'
]
)
}))
}
Solution 13 - Java
some comments mentioned the deprecation warning. to solve just use the getter:
afterEvaluate {
getClassDirectories().from(files(classDirectories.files.collect {
fileTree(dir: it, exclude: 'com/blah/**')
}))
}
Solution 14 - Java
add below config in gradle.properties file
coverageExcludeClasses=["com.example.package.elasticsearch.*", "com.example.package2.*",]
Solution 15 - Java
Gradle 6.8.3 thrown an exception.
Cannot set the value of read-only property 'classDirectories' for task ':jacocoTestReport' of type org.gradle.testing.jacoco.tasks.JacocoReport.
so I found a way to fix the issue by using
classDirectories.setFrom(
fileTree(dir: "build/classes/java/main")
.filter({file -> !file.path.contains('/dir1')})
.filter({file -> !file.path.contains('/dir2')})
.filter({file -> !file.path.contains('/dir3')})
)
Solution 16 - Java
Here is my working config in Gradle with Jacoco 0.8.5 :
def jacocoExclusions = [
'**/config/*Config.class',
'**/config/*Advice.class',
'**/security/*AuthorityRoles.class',
'**/*Application.class'
];
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination file("${buildDir}/reports/jacocoHtml")
}
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it,
exclude: jacocoExclusions
)
}))
}
}
jacocoTestCoverageVerification {
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it,
exclude: jacocoExclusions
)
}))
}
violationRules {
rule {
excludes = jacocoExclusions
limit {
minimum = 0.90
}
}
}
}