Wednesday, January 18, 2017

Jacoco, Surefire & Argline: Why jacoco.exe isn't created

Abstract

Are you using Jacoco to give you statistics on the unit test coverage of your source code? Have you encountered a problem where jacoco.exe is not created by jacoco-maven-plugin?. Then keep reading, I’ve got your answer.

Disclaimer

This post is solely informative. Critically think before using any information presented. Learn from it but ultimately make your own decisions at your own risk.

Requirements

I did all of the work for this post using the following major technologies. You may be able to do the same thing with different technologies or versions, but no guarantees.

  • Java 1.8.0_65_x64
  • jacoco-maven-plugin 0.7.5.201505241946
  • maven-surefire-plugin 2.17
  • Maven 3.0.5 (Bundled with NetBeans)

Watch out for <argLine>

If you have been using Jacoco and suddenly the jacoco.exe is not created, then chances are you have an <argLine> problem. Jacoco connects itself to the surefire plugin by editing the <argLine> value of that plugin. If you don’t set <argLine> then you’re fine. But if you do, you’ll mess up Jacoco if you don’t do it properly.

Let’s take a look at how NOT to do it. The <properties> tag is typically used to configure plugins and Listing 1 shows you what NOT to do.

Listing 1 - Don’t use <properties> to configure plugins

<properties>
  <!-- Do not configure plugin with properties -->
  <surefire.plugin.argline>-XX:PermSize=256m -XX:MaxPermSize=1048m</surefire.plugin.argline>
</properties>

Instead, configure <argLine> in the plugin itself, and include in the configuration the assumption that Jacoco has already set the <argLine> value. Listing 2 shows how to properly configure Surefire.

Listing 2 - Prepend Jacoco’s argLine value to your value

<build>
  <plugins>
      ...
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
           <argLine>${argLine} -XX:PermSize=256m -XX:MaxPermSize=1048m</argLine>
         </configuration>
      </plugin>
      ...
  </plugins>
</build>

This may look a little funny - <argLine>${argLine} -XX:PermSize=256m -XX:MaxPermSize=1048m</argLine> - but this is really nothing more than string concatenation. The Jacoco plugin automatically sets the value argLine. So if you need to set its value too, you use a standard variable reference to ${argLine} to prepend Jacoco’s value to your value. Finally, Listing 3 shows a very basic jacoco-maven-plugin configuration.

Listing 3 - Very basic Jacoco configuration

<build>
  <plugins>
    ...
    <plugin>
      <groupId>org.jacoco</groupId>
      <artifactId>jacoco-maven-plugin</artifactId>
      <version>0.7.5.201505241946</version>
      <configuration>
        <excludes>
          <exclude>org/company/*</exclude>
        </excludes>
      </configuration>
      <executions>
        <execution>
          <id>default-prepare-agent</id>
          <phase>initialize</phase>
          <goals>
            <goal>prepare-agent</goal>
          </goals>
        </execution>
        <execution>
          <id>default-check</id>
          <phase>verify</phase>
          <goals>
            <goal>check</goal>
          </goals>
          <configuration>
            <rules>
              <rule implementation="org.jacoco.maven.RuleConfiguration">
                <element>BUNDLE</element>
                <limits>
                  <limit implementation="org.jacoco.report.check.Limit">
                    <counter>INSTRUCTION</counter>
                    <value>COVEREDRATIO</value>
                    <minimum>0.0</minimum>
                  </limit>
                  <limit implementation="org.jacoco.report.check.Limit">
                    <counter>BRANCH</counter>
                    <value>COVEREDRATIO</value>
                    <minimum>0.0</minimum>
                  </limit>
                  <limit implementation="org.jacoco.report.check.Limit">
                    <counter>CLASS</counter>
                    <value>MISSEDCOUNT</value>
                    <maximum>1000</maximum>
                  </limit>
                </limits>
              </rule>
            </rules>
          </configuration>
        </execution>
        <execution>
          <id>default-report</id>
          <phase>verify</phase>
          <goals>
            <goal>report</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
    ...
  </plugins>
</build>

In listing 3, you can see the prepare-agent goal is configured to be executed at the initialize phase of the Maven life cycle. This goal is what sets the <argLine> value. Then, when the Surefire plugin runs, the jacoco.exe file gets created correctly and the unit test statistics are collected.

Summary

If jacoco.exe is not being created for you, the <argline> value is moste likely your problem. Remove any <properties> that set the argline value and configure <argLine> in the plugin itself. When you do so, remember to include Jacoco’s value by prepending the value like <argLine>${argLine} -XX:PermSize=256m -XX:MaxPermSize=1048m</argLine>.

References

Ryan Nelson. (2016, September 27). jacoco’s prepare-agent not generating jacoco.exec file [Web log comment]. Retrieved from http://stackoverflow.com/questions/21633277/jacocos-prepare-agent-not-generating-jacoco-exec-file.

Hoffmann, Marc R. (2013, October 3). jacoco.exec file is not generated after running jacoco maven ‘prepare-agent’ goal [Web log comment]. Retrieved from https://groups.google.com/forum/#!topic/jacoco/LzmCezW8VKA.

jacoco:prepare-agent. (n.d.). In EclEmma. Retrieved January 12, 2017, from http://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html.