Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jacoco code coverage dropped with migration to Java 11

I have several Gradle projects that were built using Java 8, and after converting them recently to use Java 11, Jacoco code coverage reports have been reporting much lower percentages than before. On one project, immediately after the transition, my coverage dropped from 81% to 16%.

I tried updating the Jacoco plugin to 0.8.3 (which has official JDK 11 support), Gradle to 5.4, and TestNG to 6.14.3 (not sure if this has any effect; thought it couldn't hurt to be on the latest version). Even after these changes, the project I mentioned above has 16% coverage. I manually checked a few of the classes it reported 0% coverage on and found that they actually did have test coverage on them.

For example, I added this method to one of my classes:

public String helloWorld(){
        return "hello";
    }

I then used it in a test:

@Test(groups = IntegrationTest.INTEGRATION_GROUP)
    public void testHelloWorld() {
        String helloWorld = authManager.helloWorld();
        assertEquals(helloWorld, "hello");
    }

And the coverage reported as 0:

enter image description here

If it's helpful, here are my Jacoco Gradle settings. I'm using a custom plugin to configure them.

  class ManagedJacocoPlugin implements ManagedPlugin {
  @Override
  void apply(PluginManager pluginManager) {
    pluginManager.apply(JacocoPlugin.class)
  }

  @Override
  void configure(Project project, GradlePluginConfig pluginConfig) {
    def jacoco = project.extensions.getByName("jacoco")
    jacoco.toolVersion = "0.8.3"

    def jacocoTestReport = project.tasks.getByName('jacocoTestReport')
    jacocoTestReport.reports {
      xml.enabled false
      csv.enabled false
    }

    project.tasks.withType(Test).each { t ->
      t.jacoco {
        destinationFile = project.file("$project.buildDir/jacoco/test.exec")
      }
    }

    jacocoTestReport.dependsOn "integrationTest"
  }
}

As far as I'm able to gather, Java 11 should be fully supported for Jacoco coverage given the versions of the tools I'm using. What am I missing here?

like image 973
davidmerrick Avatar asked Apr 24 '19 21:04

davidmerrick


People also ask

What happened to my JaCoCo code coverage after switching to Java 11?

I have several Gradle projects that were built using Java 8, and after converting them recently to use Java 11, Jacoco code coverage reports have been reporting much lower percentages than before. On one project, immediately after the transition, my coverage dropped from 81% to 16%.

What is JaCoCo and how to use it?

This tutorial describes the usage of the Jacoco, which can be used to check the code coverage of Java projects. 1. Jacoco Jacoco is an open source project, which can be used to check production code for test code coverage. It creates reports and integrates well with IDEs like the Eclipse IDE.

How to use JaCoCo in Eclipse IDE with EclEmma?

Using Jacoco in the Eclipse IDE With EclEmma installed the context menu of a project also contains a Coverage As entry. And besides the debug button in the main toolbar will also be another button for running java code with code coverage analysis. Once a program is run with code coverage a Coverage View will show up in the Eclipse IDE.

What is JaCoCo Maven plugin?

1. JaCoCo Maven Plugin 1.1. JaCoCo JaCoCo is a code coverage library developed by the EclEmma team. JaCoCo embeds a runtime agent in JVM, which scans the code paths traversed by the automated tests code and creates a report for those paths.


Video Answer


1 Answers

Here is what page https://stackoverflow.com/help/mcve says about How to create a Minimal, Complete, and Verifiable example:

Make sure it's complete

Copy the code from your question into a new file or project, then run it. If it doesn't run for you, then it won't run for anyone else.

However who knows what is ManagedPlugin in your example?

But ok, let's try to follow the above advice and use what we have, pretending that we have time on guessing and that we'll be lucky to guess correctly.

Everything except ManagedPlugin after addition of many missing pieces becomes a following build.gradle

apply plugin: 'java'
apply plugin: 'jacoco'

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'org.testng', name: 'testng', version: '6.14.3'
}

test {
    useTestNG() {
        includeGroups('unit')
    }
}

task integrationTest(type: Test, dependsOn: ['test']) {
    useTestNG() {
        includeGroups('integration')
    }
}


def jacoco = project.extensions.getByName("jacoco")
jacoco.toolVersion = "0.8.3"

def jacocoTestReport = project.tasks.getByName('jacocoTestReport')
jacocoTestReport.reports {
    xml.enabled false
    csv.enabled false
}

project.tasks.withType(Test).each { t ->
    t.jacoco {
        destinationFile = project.file("$project.buildDir/jacoco/test.exec")
    }
}

jacocoTestReport.dependsOn "integrationTest"

method helloWorld goes into src/main/Example.java

class Example {
    public String helloWorld() {
        return "hello";
    }
}

method testHelloWorld goes into src/test/ExampleTest.java

import org.testng.annotations.Test;
import static org.testng.Assert.*;

class ExampleTest {
    Example authManager = new Example();

    @Test(groups = "integration")
    public void testHelloWorld() {
        String helloWorld = authManager.helloWorld();
        assertEquals(helloWorld, "hello");
    }
}

Execution of gradle clean jacocoTestReport using Gralde 5.4 and JDK 11.0.1 produces following report

report 1

Thus we can conclude that provided example is definitely not complete.

Let's try to guess againg and add into src/main/java/Example.java

    public void anotherMethod() {
    }

and into src/test/java/ExampleTest.java

    @Test(groups = "unit")
    public void test() {
       new Example().anotherMethod();
    }

Now execution of gradle clean jacocoTestReport produces following report

report 2

Seems that now we can reproduce your problem.

Why anotherMethod is not covered? Let's follow another great advice from https://stackoverflow.com/help/mcve :

Divide and conquer. When you have a small amount of code, but the source of the problem is entirely unclear, start removing code a bit at a time until the problem disappears – then add the last part back.

which also works not only for code, but for changes in versions - let's try to reverse your change of Gradle version back from 5.4 to 4.10.3 and with it execution of gradle clean jacocoTestReport produces

report 3

Thus we can conclude that something in Gradle was changed. Let's check its changelog - https://docs.gradle.org/5.0/release-notes.html contains a very interesting statement:

JaCoCo plugin now works with the build cache and parallel test execution

... the tasks running with code coverage are configured to delete the execution data just before they starts executing ...

Task integrationTest removes data collected by task test. Let's try to not use same file:

//project.tasks.withType(Test).each { t ->
//    t.jacoco {
//        destinationFile = project.file("$project.buildDir/jacoco/test.exec")
//    }
//}

jacocoTestReport.executionData(test)
jacocoTestReport.executionData(integrationTest)

Now execution of gradle clean jacocoTestReport even with Gradle 5.4 produces

report 4

like image 111
Godin Avatar answered Oct 19 '22 23:10

Godin