Gradle coverage report with jacoco for a custom test task - gradle

I've split my tests into unit & DB test suites using Junit5 tags.
I created a new test task of called dbTest to run only those test tagged with the Db tag.
Looks like this (kotlin-dsl):
val dbTest by creating(Test::class) {
useJUnitPlatform {
includeTags("db")
}
}
Now I'm trying to calculate the coverage of the DB tests but the jacoco report is always empty.
Jacoco creates a non-empty exec file in the build/jacoco dir called dbTest.exec.
But when running the jacoco test report the resulting report is empty.
I generate the DB report using a custom jacoco report task that looks like this:
val jacocoDbTestReport: JacocoReport by creating(JacocoReport::class) {
reports {
xml.isEnabled = true
html.isEnabled = true
}
executionData(file("$buildDir/jacoco/dbTest.exec"))
}

Related

Generate Jacoco report for integration tests

I've created a new test suite called integrationTest using the jvm-test-suite plugin.
Now I want to generate a jacoco report just for the integration tests.
I create a new gradle task like this:
tasks.create<JacocoReport>("jacocoIntegrationTestReport") {
group = "verification"
description = "Generates code coverage report for the integrationTest task."
executionData.setFrom(fileTree(buildDir).include("/jacoco/integrationTest.exec"))
reports {
xml.required.set(true)
html.required.set(true)
}
}
But the generated HTML/XML report is empty. I have run the integration tests before executing the task and the file integrationTest.exec exists.
Thanks
It seems the important part of the new JaCoCo report task configuration is to wire the execution data via the integrationTest task instead of the exec-file path. The official docs (see last example here) also imply that the source set must be wired as well.
Here is the full build script (Gradle 7.6) that produces a report with command:
./gradlew :app:integrationTest :app:jacocoIntegrationTestReport
// build.gradle.kts
plugins {
application
jacoco
}
repositories {
mavenCentral()
}
testing {
suites {
val integrationTest by creating(JvmTestSuite::class) {
dependencies {
implementation(project(":app"))
}
}
}
}
tasks.register<JacocoReport>("jacocoIntegrationTestReport") {
executionData(tasks.named("integrationTest").get())
sourceSets(sourceSets["integrationTest"])
reports {
xml.required.set(true)
html.required.set(true)
}
}

Gradle jacoco plugin: how to print the location of the HTML report at the end of the task execution?

I added the jacoco aggregation plugin to my build
plugins {
id("jacoco-report-aggregation")
}
When I run the task ./gradlew testCodeCoverageReport, the report is correctly generated in build/reports/jacoco/testCodeCoverageReport/html/index.html but it's kinda painful to lookup the file.
How can I simply automate gradle to print the path in the build log?
Here's the solution:
tasks.withType<JacocoReport> {
val reports = reports
doLast {
println("HTML report generated: " + reports.html.entryPoint)
}
}

How to get Jacoco reports for the Karate test feature files using gradle

How to get Jacoco reports for the Karate test feature files using Gradle.
My project is a Gradle project and I am trying to integrate jacoco report feature in my project for the karate tests. The server is running in my local on 8080 port.
I am doing the following way to generate jacoco report and please let me know is my approach correct and also give me a solution to get the jacoco report for the gradle project.
1) First I am trying to generate jacoco execution data with the help of jacocoagent.jar as follows with a Gradle task:
java -javaagent:/pathtojacocojar/jacocoagent.jar=destfile=/pathtojocofile/jacoco.exec -jar my-app.jar
2) Next, I am running a Gradle task to generate the report
project.task ('jacocoAPIReport',type: org.gradle.testing.jacoco.tasks.JacocoReport) {
additionalSourceDirs = files(project.sourceSets.main.allSource.srcDirs)
sourceDirectories = files(project.sourceSets.main.allSource.srcDirs)
classDirectories = files(project.sourceSets.main.output)
executionData = fileTree(dir: project.projectDir, includes: ["**/*.exec", "**/*.ec"])
reports {
html.enabled = true
xml.enabled = true
csv.enabled = false
}
onlyIf = {
true
}
doFirst {
executionData = files(executionData.findAll {
it.exists()
})
}
}
project.task('apiTest', type: Test) {
description = 'Runs the api tests'
group = 'verification'
testClassesDirs = project.sourceSets.apiTest.output.classesDirs
classpath =
project.sourceSets.apiTest.runtimeClasspath
useJUnitPlatform()
outputs.upToDateWhen { false }
finalizedBy jacocoAPIReport
}
I don't see any of my application's classes in the jococo.exec file. I think, bcz of that I am always getting the coverage report as 0%.
The server is running in my local on 8080 port.
I don't think that is going to work. Depending on how your code is structured you need to instrument the code of the server.
I suggest trying to get a simple unit test of a Java method to work with Gradle. If that works, then use the same approach for the server-side code and it will work.

Grouping JUnit tests with Gradle

I created a new Groovy project of integration tests and want to be able to be able to group tests together for different components. For example, some tests are only valid for a docker image, while others are for testing a webapp running locally. I'd also like to get reports for the results of the tests and also be able to run the tests over and over if needed.
The first step to grouping tests in JUnit is to create an interface to name the group. Create this in a package your test classes can reach.
If your Test Class looks like this:
package com.example.test.api.get.cert
class ByIssuedBeforeTest {
//awesome tests
}
Then create an empty interface like this:
package com.example.test
interface DockerTest {}
Now change your Test Class to look like this:
package com.example.test.api.get.cert
import org.junit.experimental.categories.Category
#Category(DockerTest.class)
class ByIssuedBeforeTest {
//awesome tests
}
You can also annotate individual tests instead of the whole class.
Now in your build.gradle file:
apply plugin: 'java'
sourceSets {
main {
java {
srcDirs = ["src/main/java", "src/main/groovy"]
}
}
test {
java {
srcDirs = ["src/test/java", "src/test/groovy"]
}
}
}
test {
outputs.upToDateWhen { false }
reports {
junitXml.enabled=true
html.enabled=true
}
}
task nondockerTest(type: Test) {
outputs.upToDateWhen { false }
useJUnit {
excludeCategories 'com.example.test.DockerTest'
}
}
task dockerTest(type: Test) {
outputs.upToDateWhen { false }
useJUnit {
includeCategories 'com.example.test.DockerTest'
}
}
The java plugin for gradle gives you the test task. In the test task we add the outputs line in order to keep the test task from ever being labeled as "UP-TO-DATE", in essence forcing gradle to always run the task when we call it instead of caching the result.
The report block enables JUnit report files to be created. They will be placed in the build/reports/tests directory. If you ran the nonDockerTest it would be build/reports/tests/nondockerTest/index.html.
The useJUnit block tells Gradle to use JUnit to run the tests as well as which category of tests to run (if using includeCategories) or category to not run (if using excludeCategories).
gradle test to run all the test.
gradle nondockerTest to run the tests not labeled as with the DockerTest category.
gradle dockerTest to run just tests labeled with the DockerTest category.
Each of these tasks will create reports in the /build/reports/tests directory.

Gradle Jacoco - coverage reports includes classes excluded in configuration

I added to a project a set of sources that don't have tests and I don't want them spoil my test coverage statistics. I configured Jacoco in the next way :
test {
jacoco{
excludes = ['org/bla/**']
includes = ['com/bla/**']
append = false
}
}
jacocoTestReport {
dependsOn test
description = "Generate Jacoco coverage reports after running tests."
reports {
xml.enabled true
html.enabled true
}
classDirectories = fileTree(dir: 'build/classes/main', include: 'com/bla/**')
sourceDirectories = fileTree(dir: 'scr/main/java', include: 'com/bla/**')
}
But anyway, when generating the report, Jacoco also includes classes from org.bla
Can someone help me ?
EDIT
After some debugging, it appears that all default outputs are added to org.gradle.testing.jacoco.tasks.JacocoReport#classDirectories in a private method org.gradle.testing.jacoco.plugins.JacocoPlugin#addDefaultReportTasks
That's visible when using such code :
jacocoTestReport {
classDirectories = files('build/classes/main/com/bla')
println("-----------------------------------------------------------")
getAllClassDirs().each { File file ->
println(file.absolutePath)
}
println("-----------------------------------------------------------")
getAdditionalClassDirs().each{ File file ->
println(file.absolutePath)
}
}
jacocoTestReport << {
println("-----------------------------------------------------------")
getAllClassDirs().each { File file ->
println(file.absolutePath)
}
println("-----------------------------------------------------------")
getAdditionalClassDirs().each{ File file ->
println(file.absolutePath)
}
}
Output
-----------------------------------------------------------
<path_here>\build\classes\main\com\bla
-----------------------------------------------------------
....more text here
-----------------------------------------------------------
<path_here>\build\classes\main\com\bla
<path_here>\build\classes\main
<path_here>\build\resources\main
-----------------------------------------------------------
So - the question is : is it possible to override somehow org.gradle.testing.jacoco.plugins.JacocoPlugin#addDefaultReportTasks method, or override completely org.gradle.testing.jacoco.plugins.JacocoPlugin class ?
Ok, found a workaround :
jacocoTestReport.doFirst{
classDirectories = files('build/classes/main/com/bla')
}
This overrides classDirectories set by JacocoPlugin class.
If you have a task names something other than
test
that runs unit tests, you should be able to generate the report adding the following task to your build.gradle file:
jacocoTestReport {
group = "Reporting"
description = "Generates Jacoco coverage reports for unit tests"
executionData = files('build/jacoco/unitTest.exec')
reports {
html.destination = 'build/reports/coverage'
}
}
This needs to be called explicitly after the task to run unit tests, e.g:
gradle unitTest jacocoTestReport

Resources