关于Java:使用Gradle过滤JaCoCo覆盖率报告

Filter JaCoCo coverage reports with Gradle

问题:

我有一个与jacoco的项目,我希望能够过滤某些类和/或包。

相关文件:

我已阅读以下文档:

雅各布官方网站:
http://www.eclemma.org/jacoco/index.html

gradle的官方jacoco文档:https://gradle.org/docs/current/userguide/jacoco_plugin.html

雅各布Github的官方问题,正在研究:
https://github.com/jacoco/jacoco/wiki/FilteringOptions
https://github.com/jacoco/jacoco/issues/14

相关的StackOverflow链接:

JaCoCo&Gradle-过滤选项(无答案)

使用Sonarrunner和Gradle从Jacoco报告中排除软件包(不使用声纳)

JaCoCo-将JSP从报告中排除(它似乎适用于Maven,我正在使用gradle)

Maven Jacoco配置-从报告不起作用的类/程序包中排除(它似乎适用于Maven,我正在使用gradle)

JaCoCo gradle插件已排除(无法使它正常工作)

Gradle Jacoco-覆盖率报告包括配置中排除的类(似乎很接近,它使用了doFirst,对我不起作用)

我尝试过的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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"]
        }
    }
}

题:

生成jacoco覆盖率报告时,如何排除某些软件包和类?


感谢Yannick Welsch

搜索Google,阅读Gradle文档并浏览了较早的StackOverflow帖子之后,我在Official gradle论坛上找到了这个答案!

1
2
3
4
5
6
7
jacocoTestReport {
    afterEvaluate {
        classDirectories = files(classDirectories.files.collect {
            fileTree(dir: it, exclude: 'com/blah/**')
        })
    }
}

资料来源:https://issues.gradle.org/browse/GRADLE-2955

我的build.gradle Java / Groovy项目的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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/**'])
        })
    }
}

如您所见,我成功地向exclude:添加了更多内容以过滤一些软件包。

来源:https://github.com/jaredsburrows/CS-Interview-Questions/blob/master/build.gradle

其他项目(例如Android)的自定义任务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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/**'])
        })
    }
}

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


对于Gradle版本5.x,classDirectories = files(...)会发出弃用警告,并且从Gradle 6.0开始完全不起作用
这是不推荐使用的排除类的方式:

1
2
3
4
5
6
7
jacocoTestReport {
    afterEvaluate {
        classDirectories.setFrom(files(classDirectories.files.collect {
            fileTree(dir: it, exclude: 'com/exclude/**')
        }))
    }
}


对我来说,与

1
2
3
4
5
6
7
8
9
10
test {
  jacoco {
    excludes += ['codeeval/**',
                 'crackingthecode/part3knowledgebased/**',
                 '**/Chapter7ObjectOrientedDesign**',
                 '**/Chapter11Testing**',
                 '**/Chapter12SystemDesignAndMemoryLimits**',
                 'projecteuler/**']
  }
}

如文档中所述
https://docs.gradle.org/current/userguide/jacoco_plugin.html#N16E62并最初询问
所以答案是:

所以如果你问我:这不是一个问题

1
excludes = ["projecteuler/**"]

要么

1
excludes += ["projecteuler/**"]

1
excludes = ["**/projecteuler/**"]

排除软件包*.projecteuler.*

test {}在项目级别,而不嵌套在jacocoTestReport


对于Gradle6
使用如下所示的内容,因为他们创建了classDirectories as final,所以我们无法重新分配它,但是存在一个setter方法classDirectories.setFrom可以使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    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/**'
                    ]
            )
        }))
    }
}

这是ANT中此问题的解决方案。可以通过在jacocoTestReport任务下添加以下内容来适应gradle。尽管jacoco并未对此进行真正的记录,但这似乎是目前筛选测试结果的唯一方法。

1
2
3
4
5
afterEvaluate {
    classDirectories = files(classDirectories.files.collect {
        fileTree(dir: it, exclude: 'excluded/files/**')
    })
}


以下代码也将类别从覆盖范围验证中排除:

1
2
3
4
5
6
7
8
jacocoTestCoverageVerification {
    afterEvaluate {
        classDirectories = files(classDirectories.files.collect {
            fileTree(dir:"${project.buildDir}/classes/main",
                    exclude: ['**/packagename/**'])
        })
    }
}

这已经有一段时间了,但是我只是碰到了这一点。我正在为所有需要的排除而苦苦挣扎。我发现这对我来说要简单得多。如果遵循Maven项目布局样式/ src / main / java和/ src / test / java,则只需将buildDir / classes / main放在classDirectories配置中,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
                     ]
        )
    }
}


为了过滤jacoco报告,需要在两个任务jacocoTestReportjacocoTestCoverageVerification中进行排除。

样例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    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)
            })
        }

        ...
    }

一些评论提到了弃用警告。解决只是使用吸气剂:

1
2
3
4
5
afterEvaluate {
    getClassDirectories().from(files(classDirectories.files.collect {
        fileTree(dir: it, exclude: 'com/blah/**')
    }))
}

在gradle.properties文件中的配置下面添加

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