Reputation: 661
We have a java project which is using gradle build tool. We are using jacoco plugin to generate test coverage report. Later we have added test suites using JVM Test Suite plugin of gradle. We have observed that all those test classes run by test suites are not getting covered in code coverage report of jacoco. So If anyone got some idea what exactly should i write in build.gradle file for accomplish this, that would be great. Thanks.
This is the build.gradle file snippet:-
plugins {
id 'java'
id 'jacoco'
id 'jvm-test-suite'
}
test {
useJUnitPlatform()
finalizedBy jacocoTestReport
}
testing {
suites {
test {
useJUnitJupiter()
}
customTest(JvmTestSuite) {
dependencies {
... // some dependencies
}
}
}
}
tasks.named('check') {
dependsOn(testing.suites.customTest)
}
dependencies {
... // some other dependencies
}
jacocoTestReport {
dependsOn test
reports {
xml.required = true
}
}
Upvotes: 2
Views: 1919
Reputation: 8088
Considering that you've defined an additional test suite (integrationTest
) and added jacoco plugin as follows:
plugins {
java
`jvm-test-suite`
jacoco
}
testing {
suites {
@Suppress("UnstableApiUsage")
named<JvmTestSuite>("test") {
useJUnitJupiter()
testType.set(TestSuiteType.UNIT_TEST)
}
@Suppress("UnstableApiUsage")
register<JvmTestSuite>("integrationTest") {
useJUnitJupiter()
testType.set(TestSuiteType.INTEGRATION_TEST)
dependencies {
configurations.named("integrationTestImplementation") {
extendsFrom(configurations.testImplementation.get())
}
implementation(project())
}
}
}
}
each time you execute either test
or integrationTest
there is a corresponding jacoco exec file created at build/(test|integrationTest).exec
Now to get html-reports (or xml/csv-reports, depending on which one you've requested in tasks.jacocoTestReport {...}
block), jacoco
plugin adds jacocoTestReport
task which transforms .exec
file into other formats. The jacocoTestReport
assumes that there is only one default test suite called test
and thus only respects build/jacoco/test.exec
.
As for now (Gradle 8.1.1), adding the jacoco-report-aggregation
plugin to the build will automatically create corresponding task to convert .exec
coverage data into other formats for any additional test suite you declare. In my example, after applying id("jacoco-report-aggregation")
, I will automatically get integrationTestCodeCoverageReport
task which will take care of transforming build/jacoco/integrationTest.exec
into html and/or other formats.
Finally, if I want to have a single aggregated coverage report in html format, I need to use the testCodeCoverageReport
task, which was also brought by introducing jacoco-report-aggregation
to the build. Based on the description ("Generates aggregated code coverage report") the goal of this task is exactly report aggregation. But you need to adjust it's configuration before using, so it becomes aware of your custom test suite:
reporting {
reports {
@Suppress("UnstableApiUsage")
named<JacocoCoverageReport>("testCodeCoverageReport") {
reportTask {
executionData.builtBy(tasks.test, tasks.named("integrationTest")) // adding dependencies between aggregate reporting and test tasks
executionData.from( // specifying paths to process coverage in .exec format
project.layout.buildDirectory.file("jacoco/test.exec"),
project.layout.buildDirectory.file("jacoco/integrationTest.exec")
)
}
testType.set("Aggregate")
}
}
}
Now to get a single aggregated coverage report in html, execute ./gadlew test integrationTest testCodeCoverageReport
UPD 2023-06-30
As for Gradle 8.1 here is the universal way to aggregate INTEGRATION_TEST coverage data in addition to UNIT_TEST coverage (without hard-coding paths to .exec
files) and to produce a single report as a result:
reporting {
reports {
@Suppress("UnstableApiUsage")
create<JacocoCoverageReport>("testCodeCoverageReportRoot") {
testType.set(TestSuiteType.UNIT_TEST)
reportTask {
executionData.from(
configurations["aggregateCodeCoverageReportResults"]
.incoming.artifactView {
lenient(true)
withVariantReselection()
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.VERIFICATION))
attribute(TestSuiteType.TEST_SUITE_TYPE_ATTRIBUTE, objects.named(TestSuiteType.INTEGRATION_TEST))
attribute(VerificationType.VERIFICATION_TYPE_ATTRIBUTE, objects.named(VerificationType.JACOCO_RESULTS))
attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.BINARY_DATA_TYPE)
}
}.files,
)
}
}
}
}
If you perform coverage aggregation in a separate module, do not forget to add your source/test code modules as a dependencies with jacocoAggregation
scope, like this:
dependencies {
jacocoAggregation(project(":my-domain-model-with-unit-tests-only"))
jacocoAggregation(project(":spring-boot-app-with-unit-and-integration-tests"))
}
Many thanks to Jendrik Johannes for his youtube video series "Understanding Gradle" and his great accompanied examples on GitHub
Upvotes: 2