I am building a SonarQube 6.2 server which is already analyzing my Java 8/Gradle 3.3 projects. When adding JaCoCo to a multimodule gradle project, I realized that SonarQube is measuring code coverage on a "per-module" basis:
If a class is located in module A
and a test for this class is located in module B
, SonarQube figures the class is not covered.
I want to measure code coverage across all modules, not on a per module basis. How do I achieve this?
There are lots of similar questions but no helpful answers, although the situation seems quite common to me. Jenkins for example does that per default.
I decided to build a blueprint on github to clarify the issue.
The main build.gradle
consists of
plugins { id "org.sonarqube" version "2.2.1" }
subprojects {
apply plugin: 'java'
apply plugin: 'jacoco'
repositories { mavenCentral() }
dependencies { testCompile "junit:junit:4.12" }
}
modA/build.gradle
is empty.
It contains 3 classes: TestedInModA
, TestedInModATest
and TestedViaModB
.
modB/build.gradle
just declares a dependency to modA
:
dependencies { compile project(':modA') }
It contains just one class: TestedViaModBTest
, testing the class TestedViaModB
located in modA
.
My (private) Jenkins instance shows 100% coverage for the two classes included while SonarQube says only the class TestedInModA
(which is tested in its own module) is covered.
How can I modify my build process to see "cross-module coverage" in SonarQube?
I would love to update my project so future visitors to this question can find a working example.
My working solution (thanks @Godin)
add the following to the subprojects
closure
tasks.withType(Test) {
// redirect all coverage data to one file
// ... needs cleaning the data prior to the build to avoid accumulating coverage data of different runs.
// see `task cleanJacoco`
jacoco {
destinationFile = file("$rootProject.buildDir/jacoco/test.exec")
}
}
add
task cleanJacoco(dependsOn: 'clean') { delete "$buildDir/jacoco" }
outside the subprojects
closure.
When you perform build JaCoCo Gradle Plugin will produce modA/build/jacoco/test.exec
and modB/build/jacoco/test.exe
that contain information about execution of tests in modA
and modB
respectively. SonarQube performs analysis of modules separately, so during analysis of modA
for the file TestedViaModB
it sees only modA/build/jacoco/test.exec
.
Most common trick to cross boundaries - is to collect all coverage information into single location. This can be done with JaCoCo Gralde Plugin
either by changing location - see destinationFile
and destPath
( since information is appended to exec
file, don't forget to remove this single location prior to build, otherwise it will be accumulating information from different builds and not just from different modules ),
either by merging all files into single one - see JacocoMerge
task. And then specify this single location to SonarQube as sonar.jacoco.reportPath
.
Another trick: SonarQube 6.2 with Java Plugin 4.4 supports property sonar.jacoco.reportPaths
allowing to specify multiple locations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With