150
votes

Problem:

I have a project with and I want to be able to filter certain classes and/or packages.

Related Documentation:

I have read the following documentation:

Official site: http://www.eclemma.org/jacoco/index.html

Official docs for : https://gradle.org/docs/current/userguide/jacoco_plugin.html

Official Github issues, working on coverage: https://github.com/jacoco/jacoco/wiki/FilteringOptions https://github.com/jacoco/jacoco/issues/14

Related StackOverflow Links:

JaCoCo & Gradle - Filtering Options (No answer)

Exclude packages from Jacoco report using Sonarrunner and Gradle (Not using )

JaCoCo - exclude JSP from report (It seems to work for , I am using )

Maven Jacoco Configuration - Exclude classes/packages from report not working (It seems to work for , I am using )

JaCoCo gradle plugin exclude (Could not get this to work)

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 coverage reports?

15
A third party option (FD I'm founder of): If you upload reports to Codecov you can ignore any files you like after the fact in the features section of the product. Thanks.Steve Peak
@StevePeak So you can filter by packages online using Codecov? Also, I saw the Github, what about Android support, I saw Java. I should still have to send you all of the reports then filter after vs filtering before.Jared Burrows
You can filter based on a regexp method of any filed you do not want to include. All java is supported via Jacoco reports. Just filtering after the fact on Codecov works. It will remember your filters and apply it to all future reports. Thanks!Steve Peak
I'm curious; what does the excludes from the official documentation actually do then? Is it pretty much useless?Vivin Paliath
That excludes is not on the coverage task, but on the test task. It excludes files from being instrumented by JaCoCo and thus coverage being recorded. You can use this if you don't want to record coverage for some classes, if you cannot because of some conflict with another instrumenting agent, or because you pre-instrumented classes. This will not exclude a class from the report, especially in the last case mentioned, this would be a horrible idea.Vampire

15 Answers

141
votes

Thanks to, Yannick Welsch:

After searching Google, reading the Gradle docs and going through older StackOverflow posts, I found this answer on the Official 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

89
votes

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

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

15
votes

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

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

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)
            })
        }

        ...
    }



5
votes

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
                     ]
        )
    }
}
4
votes

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

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'
            ]
    )
}))
}
3
votes

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
2
votes

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

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
    }
}
1
votes

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

0
votes

add below config in gradle.properties file

coverageExcludeClasses=["com.example.package.elasticsearch.*", "com.example.package2.*",]

0
votes

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')})
    )