Filter JaCoCo coverage reports with Gradle

JavaUnit TestingGradleCode CoverageJacoco

Java Problem Overview


Problem:

I have a project with [tag:JaCoCo] and I want to be able to filter certain classes and/or packages.

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

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

Thanks to, Yannick Welsch:

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

Solution to my build.gradle for Java/Groovy projects:

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/**'])
        })
    }
}

Source: https://github.com/jaredsburrows/android-gradle-java-app-template/blob/master/gradle/quality.gradle#L59

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 of exclude. 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, use classDirectories.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
      }
    }
  }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJared BurrowsView Question on Stackoverflow
Solution 1 - JavaJared BurrowsView Answer on Stackoverflow
Solution 2 - JavauweView Answer on Stackoverflow
Solution 3 - Javachildno͡.deView Answer on Stackoverflow
Solution 4 - JavaAnkur SrivastavaView Answer on Stackoverflow
Solution 5 - JavaWIlkins LIangView Answer on Stackoverflow
Solution 6 - JavaAndre CompagnoView Answer on Stackoverflow
Solution 7 - JavaEmarcoView Answer on Stackoverflow
Solution 8 - JavaRandyView Answer on Stackoverflow
Solution 9 - Javaer-hanView Answer on Stackoverflow
Solution 10 - JavaShreyas PatankarView Answer on Stackoverflow
Solution 11 - JavasbzoomView Answer on Stackoverflow
Solution 12 - Javasendon1982View Answer on Stackoverflow
Solution 13 - JavariiichView Answer on Stackoverflow
Solution 14 - JavaBharat PahalwaniView Answer on Stackoverflow
Solution 15 - JavasaifView Answer on Stackoverflow
Solution 16 - JavaRandyView Answer on Stackoverflow