jacocoRootReport only shows coverage from last project of multi-project gradle build - gradle

I'm upgrading my Gradle 4 multi-project setup to Gradle 6. I've followed instructions here:
https://stackoverflow.com/a/56181389
and I've bumped the jacoco version to 0.8.5. Right now the only problem is that the human-readable coverage report seems to be missing most of the coverage data that it was showing under the old version. It seems that the coverage report is only reflecting the last (most recently tested) project. It used to work fine under Gradle 4. I'm using Java 8.
I ran the gradle build using --debug, and I notice that the test.exec file is deleted repeatedly, once for each subproject that has tests. I think this is the problem, but I don't know how to prevent deletion of this file.
2020-04-16T09:16:21.048-0600 [DEBUG] [org.gradle.internal.file.impl.DefaultDeleter] Deleting /Users/bishop/dev/aep/edge-profile-lookup-target/build/jacoco/test.exec
Can someone please help me fix this so that all of the coverage (from each of the tests which ran against each of the sub projects) appear in a single coverage report?
Here are the parts of the main build.gradle file that seem relevant:
buildscript {
ext {
jacocoVersion = '0.8.5'
...
}
...
}
allprojects {
...
apply plugin: 'jacoco'
...
}
subprojects {
tasks.withType(Test) {
// redirect all coverage data to one file
jacoco {
destinationFile = file("$rootProject.buildDir/jacoco/test.exec")
}
}
jacoco {
toolVersion = jacocoVersion
}
jacocoTestReport {
additionalSourceDirs.from = files(sourceSets.main.allSource.srcDirs)
sourceDirectories.from = files(sourceSets.main.allSource.srcDirs)
classDirectories.from = files(sourceSets.main.output.collect {
fileTree(dir: it, exclude: project.properties['BUILD_COVERAGE_EXCLUSIONS'].tokenize(','))
})
reports {
html.enabled = true
xml.enabled = true
csv.enabled = false
}
}
}
task jacocoRootReport(type: JacocoReport) {
dependsOn = subprojects.test
additionalSourceDirs.from = files(subprojects.sourceSets.main.allSource.srcDirs)
sourceDirectories.from = files(subprojects.sourceSets.main.allSource.srcDirs)
classDirectories.from = files(subprojects.jacocoTestReport.classDirectories)
executionData.from = files(subprojects.jacocoTestReport.executionData)
reports {
html.enabled = true
xml.enabled = true
csv.enabled = false
}
onlyIf = {
true
}
doFirst {
executionData.from = files(executionData.findAll {
it.exists()
})
}
}
...
apply plugin: 'jacoco'
configurations.create("jacoco")
configurations {
jacoco
}
dependencies {
jacocoAnt group: 'org.jacoco', name: 'org.jacoco.ant', version: jacocoVersion
jacocoAnt group: 'org.ow2.asm', name: 'asm', version: asmVersion
}
task copyRuntimeLibs(type: Copy) {
from configurations.jacoco
into "$rootProject.buildDir/libs"
}
build.dependsOn copyRuntimeLibs

The following:
jacoco {
destinationFile = file("$rootProject.buildDir/jacoco/test.exec")
}
configures Jacoco to always use the same output file.
So the issue is most likely that more recent Gradle versions work on separating colliding outputs.
I would recommend looking at the recently published sample on how to setup Jacoco in a multi project instead of attempting to rely on colliding outputs.

Related

jacocoTest exclusion has no effect

I have a gradle project and I want to exclude some directories from TC coverage. This is what I am giving in the task
jacocoTestReport {
reports {
xml.enabled true
csv.enabled false
html.enabled true
}
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it).exclude(
// define here
'com/this/that'
)
}))
}
}
However the classes still shows up in the coverage.
What am I missing?
afterEvaluate runs in Gradle's configuration phase which is before any tasks have executed and before any classes have been compiled (see build phases)
I'm guessing you want something like
test {
jacoco {
excludes = ['com/this/that/*']
}
}

JaCoCo gradle plugin ignoring version

Gradle Version: 6.1.1
Android Gradle Plugin: 4.0.0
When trying to run my jacoco coverage it does not appear to be taking into account the version. When I look at the HTML report it states "Created with JaCoCo 0.7.9.201702052155" despite me having toolVersion = "0.8.5" in my setup. The report also does not have fixes that I expect in 0.8.3 relating to Kotlin as a secondary confirmation this isn't working.
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.8.5"
reportsDir = file("$buildDir/reports")
}
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
jacoco.excludes = ['jdk.internal.*']
}
project.afterEvaluate {
(android.hasProperty('applicationVariants')
? android.'applicationVariants'
: android.'libraryVariants').all { variant ->
def variantName = variant.name
def unitTestTask = "test${variantName.capitalize()}UnitTest"
def uiTestCoverageTask = "create${variantName.capitalize()}CoverageReport"
tasks.create(name: "${unitTestTask}Coverage", type: JacocoReport, dependsOn: [
"$unitTestTask",
"$uiTestCoverageTask"
]) {
group = "Reporting"
description = "Generate Jacoco coverage reports for the ${variantName.capitalize()} build"
reports {
html.enabled = true
xml.enabled = true
csv.enabled = false
}
def fileFilter = [
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*',
'**/com/example/databinding/*',
'**/com/example/generated/callback/*',
'**/android/databinding/*',
'**/androidx/databinding/*',
'**/di/module/*',
'**/*MapperImpl*.*',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/*Component*.*',
'**/*BR*.*',
'**/Manifest*.*',
'**/*$Lambda$*.*',
'**/*Companion*.*',
'**/*Module.*',
'**/*Dagger*.*',
'**/*MembersInjector*.*',
'**/*_Factory*.*',
'**/*_Provide*Factory*.*',
'**/*Extensions*.*',
'**/*$Result.*', /* filtering `sealed` and `data` classes */
'**/*$Result$*.*'/* filtering `sealed` and `data` classes */
]
classDirectories.setFrom(files([
fileTree(dir: "${buildDir}/tmp/kotlin-classes/${variantName}", excludes: fileFilter)
]))
def coverageSourceDirs = [
"$project.rootDir/app/src/main/java",
"$project.projectDir/src/${variantName}/java"
]
additionalSourceDirs.setFrom(files(coverageSourceDirs))
sourceDirectories.setFrom(files(coverageSourceDirs))
def uiTestsData = fileTree(dir: "${buildDir}/outputs/code_coverage/${variantName}AndroidTest/connected/", includes: ["**/*.ec"])
executionData(files([
"$project.buildDir/jacoco/${unitTestTask}.exec",
uiTestsData
]))
}
}
}
As stated from #Bilgehan KALKAN here, as of Gradle 7, this seems to be resolved.
android {
//Other configurations...
testCoverage.jacocoVersion = "0.8.7"
}
For lower gradle version try adding this to your Project Gradle file.
subprojects {
configurations.all {
resolutionStrategy {
eachDependency { details ->
if ('org.jacoco' == details.requested.group) {
details.useVersion "0.8.6"
}
}
}
}
}
You don't need to override version as mentioned on #LethalMaus's answer. You only need to specify jacoco version under android as testCoverage.jacocoVersion, jacoco.version approach on #Alexy Nikitin's answer has been deprecated and replaced with testCoverage.jacocoVersion.
If you do not specify any version, it will use DEFAULT_VERSION under JacocoOptions class. Which is "0.8.3" for Android Gradle Plugin version 7.0.2.
You should declare jacoco version in the android gradle plugin too:
android {
jacoco {
version "<your jacoco version>"
}
}

CorDapp JaCoCo Code Coverage

I have a Corda based project with several CorDapp sub projects. I've been looking to add JaCoCo code coverage to this project. I'm looking to have a single code coverage report draw in an aggregate report of all the subproject JaCoCo reports.
To add JaCoCo to a maven project with several maven sub projects, I followed this blog entry https://lkrnac.net/blog/2016/10/aggregate-test-coverage-report/. After we ran the build ./gradlew clean test and got our reports, one of our team members noted that the whitelists weren't being created properly anymore when we ran ./gradlew clean deployNodes.
I've gone back to the base Kotlin CorDapp template found here https://github.com/corda/cordapp-template-kotlin to rule out if it's something we've done wrong with our project structure/gradle. Without JaCoCo added, I see all the whitelist entries I would expect. Once I add the JaCoCo code, I only see the 5 default Corda whitelist entries, and none of my added contract entries.
I'm using JaCoCo version 0.8.1 and coveralls version 2.6.3. The changes I've made are all within the build.gradle file for the root directory cordapp-template-kotlin:
subprojects {
repositories {
mavenCentral()
}
apply plugin: 'jacoco'
apply plugin: 'java'
group = 'net.lkrnac.blog'
version = '1.0-SNAPSHOT'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
dependencies {
testCompile("junit:junit:4.12")
}
jacoco {
toolVersion = jacoco_version
}
//command for generating subproject coverage reports
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination file("${buildDir}/jacocoHtml")
}
}
}
def publishedProjects = subprojects.findAll()
task jacocoRootReport(type: JacocoReport, group: 'Coverage reports') {
description = 'Generates an aggregate report from all subprojects'
dependsOn(publishedProjects.test)
additionalSourceDirs = files(publishedProjects.sourceSets.main.allSource.srcDirs)
sourceDirectories = files(publishedProjects.sourceSets.main.allSource.srcDirs)
classDirectories = files(publishedProjects.sourceSets.main.output)
executionData = files(publishedProjects.jacocoTestReport.executionData)
doFirst {
executionData = files(executionData.findAll { it.exists() })
}
reports {
html.enabled = true // human readable
xml.enabled = true // required by coveralls
}
}
coveralls {
sourceDirs = publishedProjects.sourceSets.main.allSource.srcDirs.flatten()
jacocoReportPath = "${buildDir}/reports/jacoco/jacocoRootReport/jacocoRootReport.xml"
}
tasks.coveralls {
dependsOn jacocoRootReport
}
I believe that the problem is coming from simply adding a task where JacocoReport as a parameter. Any thoughts how I could proceed to have both code coverage, along with building my whitelists correctly?
I have managed to find how to fix the coverage/whitelisting issue. I started stripping away what seemed to be unnecessary code within the subprojects spec, and found that removing everything except the apply plugin:, jacoco, and jacocoTestReport commands yielded both the root Jacoco code coverage, along with the necessary whitelisting. I didn't need to change any of the other code above to get the whitelisting to work.
For reference, subprojects now looks like this:
subprojects {
apply plugin: 'jacoco'
apply plugin: 'kotlin'
jacoco {
toolVersion = jacoco_version
}
//command for generating subproject coverage reports
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination file("${buildDir}/jacocoHtml")
}
}
}

Could not find method jacocoTestCoverageVerification()

I want to make jacoco plugin to fail when test coverage is not enough. I use example from gradle page :
https://docs.gradle.org/current/userguide/jacoco_plugin.html
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.7.6.201602180812"
reportsDir = file("output/jacoco/customJacocoReportDir")
}
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.enabled true
html.destination file("output/jacoco/jacocoHtml")
}
}
jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = 0.5
}
}
rule {
enabled = false
element = 'CLASS'
includes = ['org.gradle.*']
limit {
counter = 'LINE'
value = 'TOTALCOUNT'
maximum = 0.3
}
}
}
}
However, I get error:
Could not find method jacocoTestCoverageVerification() for arguments [build_4v41fim1xdl76q49oxk7mnylv$_run_closure6#18601994] on root project 'demo' of type org.gradle.api.Project.
Can anyone advise?
According to the the docs for Gradle version 3.4 or higher :
For projects that also apply the Java Plugin, The JaCoCo plugin automatically adds the following tasks:
jacocoTestReport [...]
jacocoTestCoverageVerification [...]
If the code block in your question shows your full build.gradle file, this would mean that you need to add the line that applies the Java Plugin (apply plugin: 'java').
Of course, you could also add a task of type JacocoCoverageVerification called jacocoTestCoverageVerification to your build file on your own:
task jacocoTestCoverageVerification(type: JacocoCoverageVerification) {
// configuration
}
Try using latest version of gradle. This may solve your problem

gradle jacocoTestReport is not working?

I have tried to get code coverage in a spring-gradle project using gradle jacoco plugin.
The build.gradle contains the following
apply plugin: "jacoco"
jacoco {
toolVersion = "0.7.1.201405082137"
reportsDir = file("$buildDir/customJacocoReportDir")
}
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination "${buildDir}/jacocoHtml"
}
}
I then ran
gradle test jacocoTestReport
Where after only the file test.exec is generated in build/reports folder.
Other than that nothing happens.
How can I get the HTML report?
You don't have to configure reportsDir/destinationFile
Because jacoco has default values for them.
build.gradle:
plugins {
id 'java'
id 'jacoco'
}
jacocoTestReport {
reports {
xml.enabled true
html.enabled true
csv.enabled true
}
}
repositories {
jcenter()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
Run gradle test jacocoTestReport
You can find the test report in ./build/reports/jacoco/test directory.
HTML output is in ./build/reports/jacoco/test/html directory.
Following helped . its in samples/testing/jacaco of gradle-2.3-all.zip from https://gradle.org/releases/
apply plugin: "java"
apply plugin: "jacoco"
jacoco {
toolVersion = "0.7.1.201405082137"
reportsDir = file("$buildDir/customJacocoReportDir")
}
repositories {
mavenCentral()
}
dependencies {
testCompile "junit:junit:4.+"
}
test {
jacoco {
append = false
destinationFile = file("$buildDir/jacoco/jacocoTest.exec")
classDumpFile = file("$buildDir/jacoco/classpathdumps")
}
}
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination "${buildDir}/jacocoHtml"
}
}
Unfortunately, none of these answers worked for me.
I had a similar issue.
Only different in not having the exec file generated.
And because of that ,
I found that the jacocoTestReport was simply "skipped".
I got it fixed by adding :
apply plugin: 'jacoco'
test {
useJUnitPlatform()
finalizedBy jacocoTestReport // report is always generated after tests run
}
jacocoTestReport {
...
...
...
...
}
That's because I'm using Junit5 with spring boot 2.X
subprojects {
apply(plugin: 'org.jetbrains.kotlin.jvm')
repositories {
jcenter()
mavenCentral()
}
}
task codeCoverageReport(type: JacocoReport) {
// Gather execution data from all subprojects
executionData fileTree(project.rootDir.absolutePath).include("**/build/jacoco/*.exec")
// Add all relevant sourcesets from the subprojects
subprojects.each {
sourceSets it.sourceSets.main
}
reports {
xml.enabled true
html.enabled true
csv.enabled false
}
}
// always run the tests before generating the report
codeCoverageReport.dependsOn {
subprojects*.test
}
sonarqube {
properties {
property "sonar.projectKey", "your_project_key"
property "sonar.verbose", true
property "sonar.projectName", "Your project name"
property "sonar.coverage.jacoco.xmlReportPaths", "${rootDir}/build/reports/jacoco/codeCoverageReport/codeCoverageReport.xml"
}
}
Command to run test with coverage:
./gradlew codeCoverageReport
./gradlew sonarqube -x test (test is excluded since already run and sonarqube by default executes test)
The second command can be ignored if sonarqube is not being used.
Two things to be noted that made it work:
To make available sourcesets of all modules, looping over subprojects and accumulating sourcesets worked. subprojects.sourceSets.main.allSource.srcDirs did not work.
sonar.jacoco.reportPaths is deprecated. We need to use sonar.coverage.jacoco.xmlReportPaths. Check the documentation here

Resources