Aggregated jacoco.exec but still enforce coverage threshold check per module

1,719 views
Skip to first unread message

vered.co...@gmail.com

unread,
Jun 11, 2018, 1:26:51 PM6/11/18
to JaCoCo and EclEmma Users
Hi,

I have a multi maven java project and I succeeded to create jacoco.exec file per module.

This is the relevant part in the parent pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>group.id</groupId>
<artifactId>java-parent</artifactId>
<version>2.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Java Tools</name>
<modules>
<module>module1</module>
<module>module2</module>
<module>module3</module>
</modules>
<prerequisites>
<maven>3.3.9</maven>
</prerequisites>
<properties>
<!-- JaCoCo thresholds -->
<jacoco.percentage.instruction>0.800</jacoco.percentage.instruction>
<!-- Sonar -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.jacoco.reportPaths>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPaths>
<sonar.exclusions>
**/JavaProjectApiXSAModule.java,
**/JavaProjectApiCPModule.java
</sonar.exclusions>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.core</artifactId>
<version>0.7.9</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<!-- http://mvnrepository.com/artifact/org.apache.maven.plugins/maven-surefire-plugin -->
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/Test*Unit*</include>
</includes>
<reuseForks>false</reuseForks>
<argLine>-Xmx2048m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${project.build.directory} @{argLine}</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<destFile>${sonar.jacoco.reportPaths}</destFile>
<append>true</append>
<excludes>
<exclude>com.sun.*</exclude>
</excludes>
</configuration>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>jacoco-report</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>jacoco-check</id>
<phase>test</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>INSTRUCTION</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.percentage.instruction}</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

As you can see:
1. I configured jacoco.percentage.instruction which I override in each sub module to adjust the coverage threshold accordingly.
2. Until I added the following configuration:
<destFile>${sonar.jacoco.reportPaths}</destFile>
<append>true</append>
I was able to make the build fail in case the coverage did not meet the defined threshold.
3. I added this destFile and append=true configuration as suggested here: https://stackoverflow.com/questions/13031219/how-to-configure-multi-module-maven-sonar-jacoco-to-give-merged-coverage-rep?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
I wanted sonar to consume the jacoco.exec files from each module.
I tried before to use sonar.reportPaths and to point to the different modules but that didn't work out and I had to find a way to show % in our sonar and this is the only way I found.

Is there a way to "enjoy from both worlds"? i.e. fail the build when coverage threshold is not met per module and to aggregate 1 jacoco.exec for sonar?

Thank you very much in advance!
Vered

Marc Hoffmann

unread,
Jun 12, 2018, 7:20:44 AM6/12/18
to jac...@googlegroups.com
Hi Vered,

thanks for the detailed description! From my point of view these are
your options (in that priority)

1) Clarify why you need the aggregated exec file for SonarQube, maybe
contact their mailing list. SonarQube normally perfectly works without
separate exec files (See for example
https://sonarcloud.io/dashboard?id=org.jacoco%3Aorg.jacoco.build)
2) Use our merge goal to create the aggregated exec file separately

Regards,
-marc

Evgeny Mandrikov

unread,
Jun 12, 2018, 9:59:15 AM6/12/18
to JaCoCo and EclEmma Users
Hi Vered,

You changed "destFile" property for "jacoco:prepare-agent" ( https://www.jacoco.org/jacoco/trunk/doc/prepare-agent-mojo.html )
"jacoco:check" reads data from file specified by "dataFile" property ( https://www.jacoco.org/jacoco/trunk/doc/check-mojo.html )

vered.co...@gmail.com

unread,
Jun 13, 2018, 10:48:00 AM6/13/18
to JaCoCo and EclEmma Users
Hello Marc, Evgeny,

Thank you very much for your help!
I posted a question to sonar ops colleagues in our organization and they are trying to help with the first thing you suggested Marc, thanks.
In the meantime I thing merge would be a good workaround..

I added this execution at the end of all the executions:
<execution>
<id>merge-results</id>
<phase>verify</phase>
<goals>
<goal>merge</goal>
</goals>
<configuration>
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<includes>
<include>*.exec</include>
</includes>
</fileSet>
</fileSets>
<destFile>${project.build.directory}/jacoco.exe</destFile>
</configuration>
</execution>
</executions>

However I just get another jacoco.exec file in each sub module target folder.

When I configured destFile to be:
<destFile>${project.basedir}/../target/jacoco.exe</destFile>
because I want to merge them in the parent target folder... I get jacoco.exec file in target folder of the parent but I don't think it is a correct merged result as its size is 9k only.... it cannot be that is contains all the jacocos - I have ten of them and each one is at least 400k...

I read few time the documentation but I'm a maven beginner so I'm probably missing something here?

Evgeny - did you mean to say that the "check" for coverage threshold should not be affected? In practice, I see it did with the above configuration...it did not failed the build when I changed to higher threshold...:(

Marc Hoffmann

unread,
Jun 14, 2018, 8:50:24 AM6/14/18
to jac...@googlegroups.com
If the merge goal is executed at the end of all executions it will only
include the exec file of the last execution and overwrite the previous
merge result. There should be only one execution which merges all
existing exec files.

Evgeny Mandrikov

unread,
Jun 14, 2018, 10:33:48 AM6/14/18
to JaCoCo and EclEmma Users


On Wednesday, June 13, 2018 at 4:48:00 PM UTC+2, vered.co...@gmail.com wrote: 

Evgeny - did you mean to say that the "check" for coverage threshold should not be affected? In practice, I see it did with the above configuration...it did not failed the build when I changed to higher threshold...:(


I said that your change of "destFile" definitely affects "check", because it reads "dataFile" which you didn't changed.

For example I have "src/main/java/Example.java":

public class Example {
  public static void foo() {
  }
}

"src/test/java/ExampleTest.java":

public class ExampleTest {
  @org.junit.Test
  public void test() {
  }
}

and "pom.xml" :

<?xml version="1.0" encoding="UTF-8"?>
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>example</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.8.1</version>
        <configuration>
          <destFile>target/new-location-jacoco.exec</destFile>
          <rules>
            <rule>
              <element>BUNDLE</element>
              <limits>
                <limit>
                  <counter>INSTRUCTION</counter>
                  <value>COVEREDRATIO</value>
                  <minimum>1</minimum>
                </limit>
              </limits>
            </rule>
          </rules>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>prepare-agent</goal>
              <goal>report</goal>
              <goal>check</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

</project>

Execution of "mvn clean verify" will succeed with following messages:

[INFO] --- jacoco-maven-plugin:0.8.1:report (default) @ example ---
[INFO] Skipping JaCoCo execution due to missing execution data file.
[INFO]
[INFO] --- jacoco-maven-plugin:0.8.1:check (default) @ example ---
[INFO] Skipping JaCoCo execution due to missing execution data file:/private/tmp/jacoco/target/jacoco.exec
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

BTW did you read your logs??

If I specify "dataFile" with value equal to "destFile", then execution of "mvn clean verify" will fail:

[INFO] --- jacoco-maven-plugin:0.8.1:report (default) @ example ---
[INFO] Loading execution data file /private/tmp/jacoco/target/new-location-jacoco.exec
[INFO] Analyzed bundle 'example' with 1 classes
[INFO]
[INFO] --- jacoco-maven-plugin:0.8.1:check (default) @ example ---
[INFO] Loading execution data file /private/tmp/jacoco/target/new-location-jacoco.exec
[INFO] Analyzed bundle 'example' with 1 classes
[WARNING] Rule violated for bundle example: instructions covered ratio is 0, but expected minimum is 1
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE

vered.co...@gmail.com

unread,
Jun 17, 2018, 11:37:38 AM6/17/18
to JaCoCo and EclEmma Users
Marc and Evgeny,

Thank you so much for you responsiveness and help!

Evgeny, I used your hint and configured dataFile the same as destFile path and it worked! The build now fails when coverage is not met + I have 1 jacoco file using the append that will be used by our sonar.

The configuration will look like this:

<dataFile>${sonar.jacoco.reportPaths}</dataFile>


<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>

<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.percentage.lines}</minimum>


</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>


We are a big organization and this way I configured jacoco and sonar will be used by other teams when I give my green light.

As you are the experts, I would appreciate if you let me know in case you recognize issues with it.

Thank you so much! I'm so happy to see it all plays together:)

Marc Hoffmann

unread,
Jun 18, 2018, 3:26:25 PM6/18/18
to jac...@googlegroups.com
Hi Vered,

glad to hear that it works for you now!

Technically it looks good to me.

I have to admit that I’m not fan of the check goal though. Especially if you have SonarQube in place anyways. My experience is that this leads to poorly written tests in practice (plain code executions without assertions) just to make the build green again.

Cheers,
-marc
> --
> You received this message because you are subscribed to the Google Groups "JaCoCo and EclEmma Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to jacoco+un...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/jacoco/b539ad88-3a09-4d7a-ad52-51f3836b324f%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

vered.co...@gmail.com

unread,
Jun 20, 2018, 7:56:22 AM6/20/18
to JaCoCo and EclEmma Users
Hi Marc,

Thank you very much for your feedback!
You are right, I will take it under consideration also.

Best Regards,
Vered

Reply all
Reply to author
Forward
This conversation is locked
You cannot reply and perform actions on locked conversations.
0 new messages