使用 Gradle 过滤 JaCoCo 覆盖率报告

问题:

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

相关文件:

我阅读了以下文件:

官方网站: Http://www.eclemma.org/jacoco/index.html

官方的 文档为 : < a href = “ https://gradle.org/docs/current/userguide/jacoco _ plugin.html”rel = “ noReferrer”> 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-从 report 中排除 JSP (它似乎适用于 ,我使用的是 )

Maven Jacoco Configuration-从报告中排除不工作的类/包 (它似乎适用于 ,我正在使用 )

JaCoCo gradle 插件排除 (无法使其工作)

Gradle Jacoco 覆盖报告包括在配置 中排除的类(似乎非常接近,它使用的是 doFirst,对我不起作用)

我试过的一个例子是:

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"]
}
}
}

问题:

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

136506 次浏览

感谢 Yannick Welsch:

在搜索了 Google,阅读了 Gradle 文档,浏览了更早的 StackOverflow 文章后,我在官方的 论坛上找到了这个答案!

jacocoTestReport {
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: 'com/blah/**')
}))
}
}

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

对于较老的级别版本,< 5.x 可能需要使用 classDirectories = files(classDirectories.files.collect {而不是 classDirectories.setFrom

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

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:添加了更多内容,以便过滤一些包。

来源: < a href = “ https://github.com/jaredsburrows/CS-Interview-questions/blob/master/build.gradle”rel = “ noReferrer”> https://github.com/jaredsburrows/cs-interview-questions/blob/master/build.gradle

其他项目(如 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/**'])
})
}
}

来源: < a href = “ https://github.com/jaredsburrows/android-gradle-java-app-template/blob/master/gradle/quality.gradle # L59”rel = “ norefrer”> https://github.com/jaredsburrows/android-gradle-java-app-template/blob/master/gradle/quality.gradle#l59

这里 是 ANT 中这个问题的解决方案。这可以通过在 jacocoTestReport任务下添加以下内容来适应分级。尽管 Jacoco 并没有对此进行记录,但它似乎是目前过滤测试结果的唯一方法。

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

这个已经有一段时间了,但是我刚刚发现了这个。我一直在努力排除所有的可能性。我发现这对我来说要简单得多。如果您遵循 Maven 项目布局样式/src/main/java 和/src/test/java,您只需将 BuildDir/classes/< em > main 放入 ClassDirectory配置中,如下所示:

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

对我来说,和他一起工作很好

test {
jacoco {
excludes += ['codeeval/**',
'crackingthecode/part3knowledgebased/**',
'**/Chapter7ObjectOrientedDesign**',
'**/Chapter11Testing**',
'**/Chapter12SystemDesignAndMemoryLimits**',
'projecteuler/**']
}
}

如文件所述 Https://docs.gradle.org/current/userguide/jacoco_plugin.html#n16e62最初问道 所以答案是:

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

excludes = ["projecteuler/**"]

或者

excludes += ["projecteuler/**"]

但是

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

排除包 *.projecteuler.*

以及项目级的 test {},而不是嵌套在 jacocoTestReport

下面的代码也将类排除在覆盖验证之外:

jacocoTestCoverageVerification {
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: "${project.buildDir}/classes/main",
exclude: ['**/packagename/**'])
})
}
}

对于 Gradle 5. x 版本,classDirectories = files(...)发出了弃用警告,从 Gradle 6.0开始根本不起作用 这是排除类的一种不被推崇的方法:

jacocoTestReport {
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: 'com/exclude/**')
}))
}
}

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

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

有些评论提到了弃用警告。要解决这个问题,只需使用 getter:

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

为了毕业六年级 使用像下面这样的东西,因为他们做了 classDirectories as final,我们不能重新分配它,但一个 setter 方法存在的 classDirectories.setFrom,可以利用

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

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

示例代码

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


...
}






对我来说,我必须排除两个地方

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

等级6.8.3抛出了一个异常。 Cannot set the value of read-only property 'classDirectories' for task ':jacocoTestReport' of type org.gradle.testing.jacoco.tasks.JacocoReport.

所以我找到了解决这个问题的方法

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

对于 Kotlin 用户,以下是我使用的方法(等级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/**")
}
})
)
}

这里建议: https://github.com/gradle/kotlin-dsl-samples/issues/1176#issuecomment-610643709

对于那些在 Kotlin DSL 疯狂寻找答案的人来说,以下就是答案:

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

对于那些还在苦苦思索如何从覆盖率报告中筛选特定软件包的人来说,下面是我使用最新库进行的配置。

   Build tool: Gradle 6.5 (also tried for 6.7)
Coverage Tool: Jacoco 0.8.5

需要考虑的事情/理由

  • 不需要 afterScript
  • 需要排除它两次,一次用于报告生成和覆盖验证
  • Intellij IDE 建议使用 excludes参数而不是 exclude
  • 在提供正则表达式时,一定要提供 .class文件,而不是 .java文件。
  • 毕业后5年级,classDirectories是一个只读字段,因此,使用 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

下面是我在 Gradle 使用 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
}
}
}
}