comparison content/Maven/sonar-vs-jacoco-vs-surefire.md @ 103:6aa2fa328a94

New blog post on sonar and maven
author Dirk Olmes <dirk.olmes@codedo.de>
date Tue, 12 May 2020 08:30:22 +0200
parents
children
comparison
equal deleted inserted replaced
102:94bbe517a174 103:6aa2fa328a94
1 Title: Generating test coverage for Sonar with maven, surefire and jacoco
2 Date: 2020-05-11
3 Lang: en
4
5 At work we're using [Sonar](https://www.sonarqube.org) to keep our code quality under control. One integral part of code quality is test coverage and Sonar offers coverage metrics in the UI. However, the [Sonar docs on code coverage](https://docs.sonarqube.org/latest/analysis/coverage/) are a bit sparse (at best) and don't tell you the exact steps to run for getting coverage with a Maven build.
6
7 With a bit of googling I was eventually able to find the correct steps to get coverage. The key to success is the [Jacoco Maven plugin](https://www.eclemma.org/jacoco/trunk/doc/maven.html). In a first Maven execution we let jacoco record coverage statistics while running the unit tests:
8
9 :::bash
10 mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent install
11
12 In the build log you see the jacoco-maven-plugin in action (we'll get back to this in a while):
13
14 [INFO] --- jacoco-maven-plugin:0.8.5:prepare-agent (default-cli) @ sonar-code-coverage ---
15 [INFO] argLine set to -javaagent:/.m2/repository/org/jacoco/org.jacoco.agent/0.8.5/org.jacoco.agent-0.8.5-runtime.jar=destfile=/sonar-code-coverage/target/jacoco.exec
16
17 Then in a second Maven execution we'll pick up those coverage statistics and convert them to XML so that Sonar can include them in its analysis:
18
19 :::bash
20 mvn org.jacoco:jacoco-maven-plugin:report org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
21
22 **Hooray! Coverage info in Sonar.**
23
24 The trouble starts when you need to pass custom arguments through surefire down to the JVM that will run the tests. This is done through the `<argLine>` configuration parameter of maven-surefire-plugin:
25
26 :::xml
27 <plugin>
28 <groupId>org.apache.maven.plugins</groupId>
29 <artifactId>maven-surefire-plugin</artifactId>
30 <configuration>
31 <argLine>-Xmx128m</argLine>
32 </configuration>
33 </plugin>
34
35 Looking back at the output of jacoco-maven-plugin above you'll notice that we're setting exactly the same `<argLine>` parameter as jacoco-maven-plugin does. If you don't take extra steps only one configuration can win - and that's the configuration you put into your pom. You have to run `mvn -X` to actually see this, though:
36
37 [DEBUG] Forking command line: /bin/sh -c cd /sonar-code-coverage && /opt/openjdk-bin-8.252_p09/jre/bin/java -Xmx128m -jar /sonar-code-coverage/target/surefire/surefirebooter9099169912642065145.jar /sonar-code-coverage/target/surefire 2020-05-12T07-39-04_225-jvmRun1 surefire3709014631518520641tmp surefire_01706858247537265191tmp
38
39 Note how the `-javaagent:...` argLine is not included in the command line arguments of the JVM that's forked to run the tests.
40
41 A way to fix this is through creative use of Maven build properties. Configure the jacoco-maven-plugin to set a different property than `argLine`:
42
43 :::xml
44 <plugin>
45 <groupId>org.jacoco</groupId>
46 <artifactId>jacoco-maven-plugin</artifactId>
47 <configuration>
48 <propertyName>surefire.argLine.sonar</propertyName>
49 </configuration>
50 </plugin>
51
52 Next, configure maven-surefire-plugin to include that property into its `<argLine>`:
53
54 :::xml
55 <plugin>
56 <groupId>org.apache.maven.plugins</groupId>
57 <artifactId>maven-surefire-plugin</artifactId>
58 <configuration>
59 <argLine>-Xmx128m @{surefire.argLine.sonar}</argLine>
60 </configuration>
61 </plugin>
62
63 Note that you have to use [late evaluation](http://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#argLine) of the property because it's not present when the Maven reactor starts but only after jacoco-maven-plugin has run.
64
65 Just one last hack is required to make the build work even if you don't run jacoco coverage as part of your build. Specify an empty property `surefire.argLine.sonar` in your project's properties so that it always exists and can be expanded.
66
67 For further reference I've put [a demo project up on github](https://github.com/dirk-olmes/sonar-code-coverage).