Tuning JaCoCo for PowerMock Coverage

Jacoco is widely preferred for on-the-fly instrumentation, however it cannot extend the same support when it comes to powermock, as powermockdoes dynamic classfile transformation which conflicts with Jacoco.

To overcome this issue, we can use an offline instrumentation i.e. the classes can be pre-instrumented with JaCoCo before powermock kicks in.

Configuration Steps

Here are the steps involved in configuring Offline Instrumentation of JaCoCo:

JaCoCo Agent

Unlike with on-the-fly instrumentation offline instrumented classes get a direct dependency on the JaCoCo runtime.

Add jacoco-agent dependency to our pom.xml, so that it will be available on the classpath and accessible by the instrumented classes.

1
2
3
4
5
6
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<version>${jacoco.version}</version>
<classifier>runtime</classifier>
</dependency>

JaCoCo Maven plugin

Add the below plugin configuration to the plugins section of your pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<executions>
<execution>
<id>default-instrument</id>
<goals>
<goal>instrument</goal>
</goals>
</execution>
<execution>
<id>default-restore-instrumented-classes</id>
<goals>
<goal>restore-instrumented-classes</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/coverage.exec</dataFile>
</configuration>
</execution>
</executions>
<configuration>
<excludes>
<exclude>com/somepack/subpack/**/*</exclude> <!-- to exclude any package -->
</excludes>
</configuration>
</plugin>

Surefire Maven plugin

Add the below configuration to provide coverage information to surefire.

1
2
3
4
5
6
7
8
9
10
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<systemPropertyVariables>
<jacoco-agent.destfile>${project.build.directory}/coverage.exec</jacoco-agent.destfile>
</systemPropertyVariables>
</configuration>
</plugin>

PowerMock Dependencies

Add the below powermock dependencies to your pom

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>${powermock.version}</version>
</dependency>

<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-core</artifactId>
<version>${powermock.version}</version>
</dependency>

<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
</dependency>

Version Compatibility

One last thing is version Compatibility. Make sure you use compatible versions.

For Jacoco Offline Instrumentation, use powermock 1.6.6 or greater.

1
2
3
<jacoco.version>0.7.7.201606060606</jacoco.version>
<powermock.version>1.7.1</powermock.version>
<junit.version>4.12</junit.version>