184

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?

Community
  • 1
  • 1
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
  • 1
    A third party option (FD I'm founder of): If you upload reports to [Codecov](https://codecov.io) you can **ignore any files** you like after the fact in the features section of the product. Thanks. – Steve Peak May 04 '15 at 19:31
  • @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 May 06 '15 at 17:02
  • 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 May 06 '15 at 17:47
  • 7
    I'm curious; what does the `excludes` from the official documentation actually *do* then? Is it pretty much useless? – Vivin Paliath Oct 30 '15 at 19:36
  • 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 Sep 25 '19 at 08:14

16 Answers16

162

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

tkruse
  • 10,222
  • 7
  • 53
  • 80
Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
  • 2
    @BradPitcher No problem! It took me a while to find the right answer. It just seems so "hackish". I hope they come up with a nicer way. – Jared Burrows May 27 '15 at 03:45
  • So, what is the correct approach if I just want to exclude one class from package? – Pedro Henrique Oct 20 '15 at 18:15
  • 2
    Something like: `exclude: ['**/*Test*.*'])` – Jared Burrows Oct 20 '15 at 18:36
  • I get the error Gradle DSL method not found: 'jacocoTestReport()'. What could be wrong? – Asker Jan 25 '16 at 02:04
  • @Asker, It looks like you are not applying the plugin: `apply plugin: jacoco`. – Jared Burrows Jan 25 '16 at 02:17
  • I added apply plugin: 'jacoco' right after apply plugin: 'com.android.application'. I think it should be ok? – Asker Jan 25 '16 at 02:19
  • now I restarted Android studio and get the following Errow "Cannot get property 'files' on null object". Any ideas? – Asker Jan 25 '16 at 02:29
  • 2
    `jacocoTestReport` only works with both `jacoco` and `java` plugins. This is not for Android. Please see my repo here for android: https://github.com/jaredsburrows/android-gradle-java-template/blob/master/common.gradle#L160 – Jared Burrows Jan 25 '16 at 03:53
  • @JaredBurrows Hi, thank you for your answer. How do i run my InstrumentationTests with this setup? They are saved in this folder "app\src\androidTest". – Asker Jan 25 '16 at 17:48
  • @JaredBurrows this link for android solution is broken. Can you please share it again or add it to your answer? Thanks – Syed Ali Oct 26 '16 at 13:54
  • @sttaq Thanks. I added it in the answer and check it out here: https://github.com/jaredsburrows/android-gradle-java-app-template/blob/master/gradle/codeQuality.gradle#L49. – Jared Burrows Oct 26 '16 at 16:02
  • Side note - I've found that excluding `**/*Constants*.*` (using wildcard for extension) will exclude a file called `Constants.java` but `**/*Constants*.java` (explicitly providing the extension) will not. – Wonko the Sane May 26 '17 at 15:19
  • In my case it is not ACTUALLY excluding them from calculation but it is just not showing them on the report. does it have to do under `beforeEvaluate` ? – Aditya Peshave Oct 31 '17 at 17:25
  • 21
    The `classDirectories =` results in this warning. `The JacocoReportBase.setClassDirectories(FileCollection) method has been deprecated. This is scheduled to be removed in Gradle 6.0. Use getClassDirectories().from(...)`. It would be great to show a solution compatible with Gradle 6.0. – Thunderforge Aug 16 '19 at 20:57
  • 6
    getting `Cannot set the value of read-only property 'classDirectories' for task ':jacocoTestReport' of type org.gradle.testing.jacoco.tasks.JacocoReport` using this configuration. Using gradle 5.6 and Java 8 – user9869932 Nov 06 '20 at 20:31
  • More straightforward: replace `files.collect { fileTree(dir: it, exclude` with `.getAsFileTree().matching { exclude ` – darw Jan 18 '23 at 14:45
99

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/**')
        }))
    }
}
Sergey
  • 3,253
  • 2
  • 33
  • 55
uwe
  • 3,931
  • 1
  • 27
  • 19
24

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

childno͡.de
  • 4,679
  • 4
  • 31
  • 57
  • 3
    This seems to give the classes 0% coverage rather than omit them altogether. I'm using JaCoCi 0.8.5 and Gradle 6.0 – tschumann Oct 29 '19 at 04:08
  • 1
    This the right way to tell jacoco to not meddle with some classes, other approaches only affect the reporting part. – bric3 Jun 12 '20 at 13:12
15

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/**'
                    ]
            )
        }))
    }
}
  • 1
    I am trying to use the below snippet in build.gradle to exclude my dtos but it is not working. I am using gradle 6.6.1 version. Let me know if any changes 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: ['**/dto/**' ] ) })) } } – Karthik Reddy Apr 22 '21 at 09:41
14

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

        ...
    }



WIlkins LIang
  • 171
  • 1
  • 6
  • actually (at least with Gradle 7.x) you don't need to set the exclusion for `jacocoTestCoverageVerification` – Dexter Legaspi Dec 26 '22 at 15:35
  • Variable can be avoided if we say `classDirectories.setFrom(tasks.jacocoTestReport.classDirectories)` – darw Jan 18 '23 at 14:45
11

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

Emarco
  • 1,385
  • 3
  • 12
  • 23
8

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/**')
    })
}
Community
  • 1
  • 1
Andre Compagno
  • 671
  • 4
  • 5
  • Alright, thank you for confirming that my findings are correct! I hope they make it easier to filter in the future or simply document how to filter using Gradle. – Jared Burrows May 07 '15 at 14:43
  • Is there any way to exclude a source set from inclusion in jacoco report? I want to exclude all source files which are located in `generated/java/` instead of `main/java`. – Amir Pashazadeh Mar 07 '18 at 07:53
  • This won't work for a clean build. afterEvaluate runs in Gradle's configuration phase which is before any tasks have executed and before any classes have been compiled. So the classes dirs will be empty – lance-java Sep 26 '20 at 08:27
7

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',
                '**/common/*/client/*Client*.class',
                '**/configuration/*ClientConfiguration.class',
                '**/model/search/*SearchService.class'
        ])
    }))
}

check.dependsOn jacocoTestCoverageVerification
Tom
  • 55,743
  • 3
  • 27
  • 35
  • Private method can be avoided via `classDirectories.setFrom(tasks.jacocoTestReport.classDirectories)` – darw Jan 18 '23 at 14:42
5

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
                     ]
        )
    }
}
Franz Wimmer
  • 1,477
  • 3
  • 20
  • 38
Randy
  • 729
  • 5
  • 14
  • Just saw this again. This was taken directly from a working config. Perhaps your version of Gradle and Jacoco were different than mine. Sorry. – Randy Oct 09 '18 at 20:12
5

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/**'])
        })
    }
}
er-han
  • 1,859
  • 12
  • 20
  • Hey, your version throws the following exception message: "Cannot set the value of read-only property 'classDirectories'". Fixed with change classDirectories -> classDirectories.from .But unfortunately my package still exists inside of the report – Oleksandr Dec 01 '21 at 10:47
5

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
    }
}
sbzoom
  • 3,273
  • 4
  • 29
  • 34
3

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'
            ]
    )
}))
}
sendon1982
  • 9,982
  • 61
  • 44
2

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/**')
    }))
}
riiich
  • 861
  • 8
  • 12
1

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
      }
    }
  }
}
Randy
  • 729
  • 5
  • 14
0

add below config in gradle.properties file

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

Bharat Pahalwani
  • 1,404
  • 3
  • 25
  • 40
0

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')})
    )
saif
  • 1,182
  • 14
  • 27