简体   繁体   English

Gradle:如何使用 jacoco 生成集成测试的覆盖率报告

[英]Gradle : How to generate coverage report for Integration test using jacoco

I am new to gradle.我是 gradle 的新手。 I am using the below code.我正在使用下面的代码。 But it generates coverage for unit test cases.但它会生成单元测试用例的覆盖率。 But it didn't generate for integration test cases.但它没有为集成测试用例生成。 I have my test classes in the package src/test/java.我在包 src/test/java 中有我的测试类。

test {
    dependsOn jettyRunWar
    ignoreFailures true
    finalizedBy jettyStop
}

apply plugin: 'jacoco'

jacocoTestReport {
    group = "Reporting"
    description = "Generate Jacoco coverage reports after running tests."
    additionalSourceDirs = files(sourceSets.main.allJava.srcDirs)
}

Using Gradle 5.4.1 (and now 5.5.1), I was able to get a report after any test task, currently I have both test and integrationTest tasks.使用 Gradle 5.4.1(现在是 5.5.1),我能够在任何测试任务之后获得报告,目前我有testintegrationTest test任务。

EDIT3 : Fixed a potential bug when executing only some test tasks EDIT3 :修复了仅执行某些测试任务时的潜在错误

  • Don't configure executionData in doLast / doFirst blocks, it was an error from my part.不要在doLast / doFirst块中配置executionData ,这是我的错误。 For more information checks this gradle github ticket有关更多信息,请查看此gradle github 票证
  • Added the more prudent alternative (again not in a doLast / doFirst block) executionData { tasks.withType(Test).findAll { it.jacoco.destinationFile.exists() }*.jacoco.destinationFile }添加了更谨慎的替代方案(再次不在doLast / doFirst块中) executionData { tasks.withType(Test).findAll { it.jacoco.destinationFile.exists() }*.jacoco.destinationFile }

EDIT2 : The solution is the same, I just tweaked EDIT2 :解决方案是一样的,我只是调整

  • the reports destination to use jacoco.reportsDir ,使用jacoco.reportsDir的报告目的地,
  • the executionData now takes tasks.withType(Test) instead of just [test, integrationTest] executionData 现在需要tasks.withType(Test)而不是[test, integrationTest]
  • setting executionData is done in the doFirst block instead of doLast设置executionDatadoFirst块而不是doLast

EDIT : After looking at the documentation of JacocoReport , there's a variant JacocoReport:executionData that take Gradle tasks directly.编辑:查看JacocoReport的文档后,有一个变体JacocoReport:executionData直接执行Gradle 任务。 It works because the JaCoCo plugin adds a JacocoTaskExtension extension to all tasks of type Test .它起作用是因为JaCoCo 插件为Test类型的所有任务添加了JacocoTaskExtension扩展 Which is then less error prone.这样就不太容易出错了。


jacocoTestReport {
    // The JaCoCo plugin adds a JacocoTaskExtension extension to all tasks of type Test.
    // Use task state to include or not task execution data
    // https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/TaskState.html
    // This declaration will be used as a closure, notice there no wrapping parenthesis
    executionData tasks.withType(Test).findAll { it.state.executed }

    // If the above instruction really don't work, there maybe some things that intervene in the process, in this case, you may be a bit more lucky with this instruction
    // executionData { tasks.withType(Test).findAll { it.jacoco.destinationFile.exists() }*.jacoco.destinationFile }

    reports {
        xml.enabled true
        xml.destination(file("${jacoco.reportsDir}/all-tests/jacocoAllTestReport.xml"))
        html.enabled true
        html.destination(file("${jacoco.reportsDir}/all-tests/html"))
    }
}

And the same trick can be applied to sonarqube task :同样的技巧可以应用于sonarqube任务:

sonarqube {
    group = "verification"
    properties {
        // https://jira.sonarsource.com/browse/MMF-1651
        property "sonar.coverage.jacoco.xmlReportPaths", jacocoTestReport.reports.xml.destination
        properties["sonar.junit.reportPaths"] += integrationTest.reports.junitXml.destination
        properties["sonar.tests"] += sourceSets.integrationTest.allSource.srcDirs
        // ... other properties
    }
}

Older but very working answer.较旧但非常有效的答案。 Also using the knowledge above (that Test s task are extended by JacocoTaskExtension ) it's possible to replace the manual file configuration of executionData by test.jacoco.destinationFile and integrationTest.jacoco.destinationFile .同样使用上面的知识( Test的任务由JacocoTaskExtension扩展),可以用test.jacoco.destinationFileintegrationTest.jacoco.destinationFile替换executionData的手动file配置。

// Without it, the only data is the binary data, 
// but I need the XML and HTML report after any test task
tasks.withType(Test) {
    finalizedBy jacocoTestReport
}

// Configure the report to look for executionData generated during the test and integrationTest task
jacocoTestReport {
    executionData(file("${project.buildDir}/jacoco/test.exec"),
                  file("${project.buildDir}/jacoco/integrationTest.exec"))
    reports {
        // for sonarqube
        xml.enabled true
        xml.destination(file("${project.buildDir}/reports/jacoco/all-tests/jacocoAllTestReport.xml"))
        // for devs
        html.enabled true
        html.destination file("${project.buildDir}/reports/jacoco/all-tests/html")
    }
}


sonarqube {
    group = "verification"
    properties {
        // https://jira.sonarsource.com/browse/MMF-1651
        property "sonar.coverage.jacoco.xmlReportPaths", ${project.buildDir}/test-results/integrationTest"
        properties["sonar.junit.reportPaths"] += "${project.buildDir}/test-results/integrationTest"
        properties["sonar.tests"] += sourceSets.integrationTest.allSource.srcDirs
        // ... other properties
    }
}

project.tasks["sonarqube"].dependsOn "jacocoTestReport"

I believe the most full answer will look like:我相信最完整的答案如下:

tasks.withType(Test) {
    finalizedBy jacocoTestReport
}

project.jacocoTestReport {
    getExecutionData().setFrom(fileTree(buildDir).include("/jacoco/*.exec"))

    reports {
        csv.enabled true
    }
}

At least it's fully suited for my needs with integration and functional testing.至少它完全适合我的集成和功能测试需求。

It seems like, what you need to tell build.gradle is where are your Intergration tests (ie folder containing those IT tests) using sourceSets.看起来,您需要告诉 build.gradle 是使用 sourceSets 的集成测试(即包含这些 IT 测试的文件夹)在哪里。 In my case, i have source under src/java (instead of src/main/java - gradle default).. my unit tests (Junit) under test/java folder, and my integration tests under src/java-test folder.就我而言,我在 src/java 下有源代码(而不是 src/main/java - gradle 默认)。我的单元测试(Junit)在 test/java 文件夹下,我的集成测试在 src/java-test 文件夹下。

sourceSets {
   main {
      java {
         srcDir 'src/java'
      }
   }
   test {
      java {
         srcDir 'test/java'
      }
      resources {
         srcDir 'test/resources'
         srcDir 'conf'
      }
   }
   integrationTest {
      java {
         srcDir 'src/java-test'
      }
   }
}

Then, I have integrationTest task as ... which you can tweak as you might not have cleanTest (custom task that i have created), so you can ignore that dependsOn... i think in your case you'll use something like jettyStart as you're using that for IT tests (starting the container for running IT tests and then finalizedBy feature to stop jetty .. jetty plugin)然后,我将 integrationTest 任务作为...您可以进行调整,因为您可能没有 cleanTest(我创建的自定义任务),因此您可以忽略该dependsOn...我认为在您的情况下,您将使用诸如 jettyStart 之类的东西当您将其用于 IT 测试时(启动容器以运行 IT 测试,然后 finalizedBy 功能以停止 jetty .. jetty 插件)

task integrationTest( type: Test, dependsOn: cleanTest ) {
   jacoco {
      //destinationFile = file("$buildDir/jacoco/jacocoTest.exec")
      destinationFile = file("$buildDir/jacoco/integrationTest.exec")
      //classDumpFile = file("$buildDir/jacoco/classpathdumps")
      classDumpFile = file("$buildDir/classes/integrationTest")
   }
   testClassesDir = sourceSets.integrationTest.output.classesDir
   classpath = sourceSets.integrationTest.runtimeClasspath
}

SEE this post for more detailed output structure and script that I have at my end.请参阅这篇文章,了解我最后拥有的更详细的输出结构和脚本。 Im getting the .exec for both Unit tests (test.exec) and IT tests intergrationTest.exec.. but Im not getting the jacoco.xml/jacocoHtml reports for both tests.我得到了单元测试 (test.exec) 和 IT 测试 intergrationTest.exec 的 .exec .. 但我没有得到两个测试的 jacoco.xml/jacocoHtml 报告。 I also found that, if I run "gradle clean build" (which includes call to "test" task) and "gradle clean build integrationTest" then, later one overwrites unit tests data in build/test-results folder and build/reports/tests folder.我还发现,如果我运行“gradle clean build”(包括对“test”任务的调用)和“gradle clean build integrationTest”,那么稍后会覆盖 build/test-results 文件夹和 build/reports/ 中的单元测试数据测试文件夹。

Jacoco Unit and Integration Tests coverage - individual and overall Jacoco 单元和集成测试覆盖范围 - 个人和整体

NOTE : in my case, jacocoTestReport is defined in the global gradle init.d folder in one of the common gradle file.注意:就我而言,jacocoTestReport 是在通用 gradle 文件之一的全局 gradle init.d 文件夹中定义的。 This will help us not to include the same code in all / at project level build.gradle file.这将帮助我们不在所有 / 在项目级别的 build.gradle 文件中包含相同的代码。

Since I couldn't make it run with any of the answers, I will add my solution here.由于我无法使用任何答案运行它,因此我将在此处添加我的解决方案。 It will work if you run your test task (eg integTest ) first and call the jacocoTestReport afterwards.如果您首先运行测试任务(例如integTest )然后调用jacocoTestReport

All you need is to tell the jacocoTestReport task where to find the gathered execution data from you test task.您只需要告诉jacocoTestReport任务在哪里可以找到从您的测试任务收集的执行数据。 The execution data is always named after the test task.执行数据总是以测试任务命名。 So if you have a test task called integTest , your execution data will be stored in build/jacoco/integTest.exec .因此,如果您有一个名为integTest的测试任务,您的执行数据将存储在build/jacoco/integTest.exec The jacocoTestReport task can be configured to look for those other files too by adding them to the property executionData. jacocoTestReport任务也可以配置为通过将它们添加到属性 executionData 来查找其他文件。 You can also add wildcards includes so all execution data is taken into consideration:您还可以添加通配符包含,以便考虑所有执行数据:

jacocoTestReport {
    executionData = fileTree(dir: project.projectDir, includes: ["**/*.exec"])
}

UPDATE As stated by @rahulmohan the executionData property has become readonly.更新正如@rahulmohan 所述, executionData 属性已变为只读。 Instead define the jacocoTestReport task as below:而是定义 jacocoTestReport 任务,如下所示:

jacocoTestReport {
    getExecutionData().from(fileTree(project.projectDir).include("/jacoco/*.exec"))

by executing the statement below the test coverage jacoco report will be created for you integration test task (eg integTest )通过执行下面的语句,将为您创建集成测试任务(例如integTest )的测试覆盖率 jacoco 报告

./gradlew integTest jacocoTestReport

This also works for multi module projects where you want to run the integTest task in module a :这也适用于要在模块a运行integTest任务的多模块项目:

./gradlew a:integTest a:jacocoTestReport

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用gradle生成单个单元测试的Jacoco代码覆盖率报告 - Generate Jacoco code coverage report for individual unit tests using gradle 带有 Jacoco 插件的 build.gradle 不会为集成测试生成覆盖率报告 - build.gradle with Jacoco plugin doesn't generate coverage report for integration tests 如何使用Gradle在Android项目中生成Jacoco报告 - How to generate jacoco report in android project with gradle Jacoco仅针对单个测试类生成覆盖率报告 - Jacoco generate coverage report for only a single test class Jenkins和Jacoco集成测试覆盖率 - Jenkins and Jacoco Integration Test Coverage 使用 gradle 从 jacoco 测试覆盖率中删除一些 java 文件 - Remove some java files from jacoco test coverage using gradle 使用Powermock时,Gradle Jacoco不会跟踪Spock测试的覆盖范围 - Gradle Jacoco does not track the coverage of Spock test when using Powermock maven jacoco 插件不生成覆盖率报告 - maven jacoco plugin does not generate coverage report 不生成 jacoco-ut.exec 覆盖率报告 - Not generate jacoco-ut.exec coverage report 使用 jacoco 离线检测的 gradle 每次测试的覆盖率 - java.lang.IllegalStateException: JaCoCo 代理未启动 - coverage per test with gradle using jacoco offline instrumentation - java.lang.IllegalStateException: JaCoCo agent not started
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM