I have a Java project consisting on multiple modules. Some functions for a common package are tested within the other modules. Sonar only shows the code coverage tested inside each package, how can I tell it to search in all the modules?
I am using SonarQube 4.5.4, Java 8 and JUnit 4.12
You have to provide SonarQube with a single JaCoCo report aggregating data from all the modules.
In the parent POM, define a location for this aggregated JaCoCo report:
<properties>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
</properties>
and configure JaCoCo (especially <destFile>)
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.6.201602180812</version>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
<append>true</append>
</configuration>
<executions>
<execution>
<id>agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
In each module, tell JaCoCo to aggregate the coverage data to this global JaCoCo report file:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
</configuration>
</plugin>
You can have a look at this project: https://github.com/racodond/sonar-css-plugin that produces an aggregated JaCoCo report used by SonarQube: https://sonarqube.com/dashboard/index?id=org.codehaus.sonar-plugins.css%3Acss
Related
I am trying to integrate my code coverage into the sonar but it shows 0.
I have integrated jacoco as below to my pom but, it still shows the code coverage as zero.
I have only used the pom file from this repository, what other configuration should I work in order to have code coverage ?
What would be other parameters should I possibly add?
https://github.com/daniel-frak/keycloak-user-migration/blob/master/pom.xml
Thanks.
Full repo:
https://github.com/daniel-frak/keycloak-user-migration
There are a number of things that can cause this.
The first thing you should do is examine the workspace to see if the Jacoco plugin wrote its output files anywhere in the "target" tree. It will generate a data file in one or more formats, but it will also generate an html tree, with an "index.html" in the root. You can visit that file, and it will show your coverage results.
If you don't find those files, then either your jacoco plugin is not properly integrated with your surefire plugin, or you simply didn't run your unit tests in the build (don't laugh, I've seen people do this).
The "integration" is done by telling Jacoco what variable to put the required command line into, and telling Surefire to use that variable.
Here is a sample jacoco plugin definition:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.maven.plugin.version}</version>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<outputDirectory>${jacoco.path}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
Note the reference to "surefireArgLine". Here is the Surefire definition that goes with that:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven.surefire.plugin.version}</version>
<configuration>
<argLine>${surefireArgLine}</argLine>
</configuration>
</plugin>
We also combine this with these property settings:
<jacoco.path>${basedir}/target/jacoco_report</jacoco.path>
<sonar.coverage.jacoco.xmlReportPaths>${basedir}/target/jacoco_report/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
I have maven setup with multiple modules, the setup looks something like this
root module
- domain module
- repository module
- service module
- controllers module
Jacoco is correctly generating test coverage from unit tests and sonar is showing the correct percentage (let's say 20%). Surefire is used for unit tests.
For integration tests its more tricky, we use failsafe and integration tests generate jacoco-it.exec file which is scanned by sonar. My problem is that integration tests are located in the controllers module and it only shows test coverage of integration tests on classes that are inside controllers and not on classes that are in another module like service module. Because of this overall test coverage with integration tests increases to something like 21% instead of 35+%.
Is it possible to configure sonar and jacoco to measure test coverage with the integration tests of all classes instead of classes from same module only, if integration tests are in controllers module?
For reference, this is the relevant setup
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
...
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${project.build.directory}/jacoco.exec</destFile>
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>pre-integration-test</id>
<phase>pre-integration-test</phase>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${project.build.directory}/jacoco-it.exec</destFile>
<propertyName>failsafeArgLine</propertyName>
</configuration>
</execution>
</executions>
</plugin>
I run my tests with mvn verify and scanner with mvn sonar:sonar
You can aggregate your coverage reports by writing them all to the same destination file.
For example, we're only covering unit tests in our multi-module projects at the moment, so our parent pom contains:
<properties>
...
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
...
</properties>
and
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
<append>true</append>
</configuration>
<inherited>true</inherited>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
This results in a single aggregated report for all modules.
I expect that a similar pattern could be applied to your jacoco IT configuration.
Gooday,
I’m trying to get my IT in to the test coverage in sonar. I have a multi module project and I want this to work for all the modules. So as far as I got it through the documentation I found:
https://docs.sonarqube.org/display/PLUG/Usage+of+JaCoCo+with+Java+Plugin
https://github.com/SonarSource/sonar-scanning-examples/tree/master/sonarqube-scanner-maven (witch are outdated btw)
http://www.eclemma.org/jacoco/trunk/doc/maven.html
Integrating JaCoCo with SONAR for unit and integration test coverage (autdated its prity based on old maven and sonar stuff and our sonar is a bit newer (6.3.1)).
But when I run it the test seems to have 0% so obviously I’m doing something wrong. Some in put on where I did go wrong would be nice.
My main Pom:
<properties>
<maven-failsafe-plugin.version>2.20.1</maven-failsafe-plugin.version>
<maven-surefire-plugin.version>2.20.1</maven-surefire-plugin.version>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.jacoco.reportPaths>${project.basedir}/../target/</sonar.jacoco.reportPaths>
<argLine>-Xmx256m -XX:MaxPermSize=200m</argLine>
</properties>
...
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin.version}</version>
<configuration>
<append>true</append>
</configuration>
<executions>
<execution>
<id>agent-for-ut</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${project.basedir}/../target/jacoco-ut.exec</destFile>
</configuration>
</execution>
<execution>
<id>agent-for-it</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${project.basedir}/../target/jacoco-it.exec</destFile>
</configuration>
</execution>
<execution>
<id>jacoco-site</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<trimStackTrace>false</trimStackTrace>
</configuration>
</plugin>
</plugins>
</build>
Ive been messing with for my feeling a whole day and have not found a clear cut answer what I am doing wrong. So some input would be very helpful
well the coverage for both unit and integration tests is a bit fragile...
The configuration you have looks ok. I think what may happens is that the "argLine" property is replaced or not correctly set for the surefire or failsafe plugin. If you run the mvn goals with -X have a close look what happens when failsafe starts what its value is. The argLine should contain the jacoco agent to collect the coverage information.
Another thing: failsafe might write the coverage results into the same jacoco.exec file as surefire.
What I've done (not sure if it's the smartest of all ways): put all things in a profile and use custom properties for the jacoco-plugin and seperate files for the coverage so the sonar report can pick them up:
The sonar-jacoco-listeners is only required if you want to know what test covers which production code. In sonar this is then shown in the green bar what tests called the code.
Other than that:
The pom has some properties:
<surefire.jvm.args></surefire.jvm.args>
<failsafe.jvm.args></failsafe.jvm.args>
<jacoco.append>true</jacoco.append>
</properties>
These can be set if needed and the config uses its own properties to not conflict with the argLine (which is the default for both surefire and failsafe)
The sonar.jacoco.reportPath can be used to write one file for all maven modules, in case some integration tests are in a different module and you want to measure the coverage as well (not too nice code-wise, but well... reality and stuff):
<sonar.jacoco.itReportPath>${project.basedir}/../target/jacoco-it.exec</sonar.jacoco.itReportPath>
Here my coverage profile: (adopt the includes: my/packages/* pattern below!)
<profile>
<dependencies>
<dependency>
<groupId>org.codehaus.sonar-plugins.java</groupId>
<artifactId>sonar-jacoco-listeners</artifactId>
<version>3.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<!-- prepare configuration for surefire tests -->
<execution>
<id>prepare-agent</id>
<phase>initialize</phase>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
<propertyName>jacoco.agent.argLine</propertyName>
<append>true</append>
</configuration>
</execution>
<!-- prepare configuration for failsafe integration tests -->
<execution>
<id>prepare-agent-integration</id>
<phase>pre-integration-test</phase>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${sonar.jacoco.itReportPath}</destFile>
<propertyName>jacoco.agent.it.argLine</propertyName>
<append>true</append>
</configuration>
</execution>
</executions>
<configuration>
<includes>
<include>my/packages/*</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<properties>
<property>
<name>listener</name>
<value>org.sonar.java.jacoco.JUnitListener</value>
</property>
</properties>
<argLine>${jacoco.agent.argLine} ${surefire.jvm.args}</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<argLine>${jacoco.agent.it.argLine} ${failsafe.jvm.args}</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
So the principle is the same, setup the jacoco agent in the correct phase and run the tests. I assume the jacoco agent is not properly setup or your argLine conflicts with something happening during your build.
My project setup is simple (all source available at github):
parent
↳ backend
↳ client
↳ integration-tests
And after runing maven:
mci sonar:sonar -Dsonar.host.url=http://localhost:9000 -Dsonar.login=12...9
I see that unit and integration tests are visible for sonar, but coverage from IT is not.
For Intelij IDEA jacoco-it.exec looks fine:
I'm assuming that culprit is here:
[INFO] Sensor JaCoCoSensor [java]
[INFO] No JaCoCo analysis of project coverage can be done since there is no class files.
[INFO] Sensor JaCoCoSensor [java] (done) | time=1ms
So I did small hack (in short: copied all source files to integration-test module):
<properties>
<sonar.sources>${basedir}/target/copied</sonar.sources>
</properties>
[...]
<!-- hack to generate coverage reports -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven-resources-plugin.version}</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>generate-sources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${sonar.sources}</outputDirectory>
<resources>
<resource>
<directory>${basedir}/../backend/src/main/java</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${sonar.sources}</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
But now all my classes ale duplicated (sonar shows also classes from ../target/copied dir):
Sonar version: 6.5
Jacoco maven plugin: 0.7.5.201505241946 (also tried lastest 0.7.9)
Any ideas what should I do here?
Looks like I have answer for that question:
Report wasn't generated because post-unit-test execution was in the wrong phase. Instead of <phase>test</phase> I now have <phase>verify</phase>
I had a wrong goal for post-integration-test. The change was from <goal>report-integration</goal> to <goal>report-aggregate</goal>:
This goal allows me to create coverage reports when tests are in separate projects from the code under test.
Added properties:
<jacoco.itReportPath>${project.basedir}/../integrations-tests/target/jacoco-it.exec</jacoco.itReportPath> and
<sonar.jacoco.reportPaths>${jacoco.itReportPath},${project.build.directory}/jacoco-it.exec,${project.build.directory}/jacoco.exec</sonar.jacoco.reportPaths>
All those chages and update project available on github
I use mainly jacoco for coverage. You need to have a few things in place before you start
Enable and configure surefire plugin
Enable and configure the jacoco plugin
It's a one time configuration that you will build and forget, one of my projects serving as parent enables this feature. Feel free to check it out:
https://github.com/slixes/parent/blob/master/pom.xml
In my Maven/Java project, I want to make sure that I always get the loading of resources right -- some can be always fetched as Files, others get packaged into the final .jar and have to be fetched as streams.
I now would have thought that this is the ideal task for the Maven failsafe plugin: I simply JUnit-test the affected methods in the Unit tests (means, that the tests are run using the classes lying in the classes folder) using surefire and in the integration tests (means, the tests are run using the classes packed into the jar) using surefire.
But when I make a demo project that throws an Exception when run from the .jar and doesn't when run from Eclipse, both the unit tests and the integration tests calling the method do not throw an exception, means that failsafe doesn't use the packaged jar at all.
How can I tie it to the jar artifact only?
My pom.xml:
<project ...>
...
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>packagingTest.MainClass</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.12</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify</id>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
... Dependency to JUnit ...
</project>