I'm trying to measure coverage using JaCoCo on this project: https://github.com/square/retrofit
Everything seems to work fine but, for some reason, several tests that used to work, fail when using JaCoCo runtime agent.
Here is (the interesting part) of my pom.xml
:
...
<plugins>
...
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.17</version>
<executions>
<execution>
<id>default-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
<configuration>
<!-- Sets the VM argument line used when unit tests are run. -->
<argLine>${surefireArgLine}</argLine>
</configuration>
</plugin>
...
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.0</version>
<executions>
<!--
Prepares the property pointing to the JaCoCo runtime agent which
is passed as VM argument when Maven the Surefire plugin is executed.
-->
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<!--
Sets the name of the property containing the settings
for JaCoCo runtime agent.
-->
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
<!--
Ensures that the code coverage report for unit tests is created after
unit tests have been run.
-->
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
The complete pom.xml
can be found here: https://pastebin.com/HSKJpS3g
All the tests are failing for the same cause, let me show an example.
Consider the class Example
declared in this test:
@Test public void customMethodNoBody() {
class Example {
@HTTP(method = "CUSTOM1", path = "/foo")
Call<ResponseBody> method() {
return null;
}
}
/* Do some operations with the class Example */
}
Later in the code Exemple.class
is passed to the method TestingUtils.onlyMethod
which will throw an exception:
package retrofit2;
import java.lang.reflect.Method;
public final class TestingUtils {
public static Method onlyMethod(Class c) {
Method[] declaredMethods = c.getDeclaredMethods();
if (declaredMethods.length == 1) {
return declaredMethods[0];
}
throw new IllegalArgumentException("More than one method declared.");
}
}
All the tests fail for this same exception being thrown, which wasn't happening before adding JaCoCo. Why is this happening ? How can I solve the problem ?
The command used by maven to run the tests is this:
/usr/lib/jvm/java-8-oracle/jre/bin/java
-javaagent:/root/.m2/repository/org/jacoco/org.jacoco.agent/0.7.5.201505241946/org.jacoco.agent-0.7.5.201505241946-runtime.jar=destfile=/root/retrofit/retrofit/target/jacoco.exec
-jar /root/retrofit/retrofit/target/surefire/surefirebooter7714471086789859732.jar
/root/retrofit/retrofit/target/surefire/surefire2679778491836039056tmp
/root/retrofit/retrofit/target/surefire/surefire_02232907551688610770tmp
Note the -javaagent
option added by JaCoCo. If you would like to have a look at the whole logs issued by mvn clean test
, you can find them here: https://pastebin.com/kUtLtyjw
Why does the coverage report not show highlighted source code? Make sure the following prerequisites are fulfilled to get source code highlighting in JaCoCo coverage reports: Class files must be compiled with debug information to contain line numbers. Source files must be properly supplied at report generation time.
JaCoCo now officially supports Java 12. Instrumentation does not add synthetic field to Java 11+ class files, however still adds synthetic method (GitHub #845). Branches added by the Kotlin compiler version 1.3.
JaCoCo now officially supports Java 15 and 16 (GitHub #1094, #1097, #1176). Experimental support for Java 17 class files (GitHub #1132). New formats parameter for Maven report goals to specify the generated report formats.
JaCoCo reports help us visually analyze code coverage by using diamonds with colors for branches, and background colors for lines: Red diamond means that no branches have been exercised during the test phase. Yellow diamond shows that the code is partially covered – some branches have not been exercised.
When using JaCoCo you want to ensure that syntethic fields and methods are not processed by your own code as JaCoCo uses them to collect the coverage statistics. Luckily both Field
and Method
have the isSynthetic()
method.
public static Method onlyMethod(Class c) {
return Arrays.stream(c.getDeclaredMethods())
.filter(m -> !m.isSynthetic())
.reduce((a, b) -> {
throw new IllegalStateException("More than one method declared.");
})
.get();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With