java - Jacoco 代码覆盖率随着迁移到 Java 11 而下降

标签 java code-coverage jacoco java-11

我有几个使用 Java 8 构建的 Gradle 项目,最近将它们转换为使用 Java 11 后,Jacoco 代码覆盖率报告报告的百分比比以前低得多。在一个项目中,在过渡之后,我的覆盖率立即从 81% 下降到 16%。

我尝试将 Jacoco 插件更新到 0.8.3(有官方 JDK 11 support),Gradle 更新到 5.4,TestNG 更新到 6.14.3(不确定这是否有任何效果;我认为打开它不会有什么坏处最新版本)。即使在这些变化之后,我上面提到的项目也有 16% 的覆盖率。我手动检查了一些报告覆盖率为 0% 的类,发现它们实际上确实有测试覆盖率。

例如,我将此方法添加到我的一个类中:

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

然后我在测试中使用了它:

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

覆盖率报告为 0:

enter image description here

如果有帮助,这是我的 Jacoco Gradle 设置。我正在使用自定义插件来配置它们。

  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"
  }
}

据我所知,考虑到我使用的工具版本,Java 11 应该完全支持 Jacoco 的覆盖范围。我在这里缺少什么?

最佳答案

这是什么页面 https://stackoverflow.com/help/mcve说到如何创建一个最小的、完整的和可验证的例子:

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.

但是谁知道您的示例中的 ManagedPlugin 是什么?

但是好吧,让我们尝试遵循上述建议并使用我们现有的东西,假装我们有时间猜测并且我们很幸运能猜对。

ManagedPlugin 之外的所有内容在添加许多缺失部分后都变成了以下 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"

方法 helloWorld 进入 src/main/Example.java

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

方法 testHelloWorld 进入 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");
    }
}

使用 Gralde 5.4 和 JDK 11.0.1 执行 gradle clean jacocoTestReport 生成以下报告

report 1

因此我们可以得出结论,所提供的示例肯定是不完整的。

让我们尝试再次猜测并添加到 src/main/java/Example.java

    public void anotherMethod() {
    }

并进入 src/test/java/ExampleTest.java

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

现在执行 gradle clean jacocoTestReport 生成以下报告

report 2

看来现在我们可以重现您的问题了。

为什么 anotherMethod 没有被覆盖?让我们听从 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.

这不仅适用于代码,还适用于版本更改 - 让我们尝试将 Gradle 版本从 5.4 更改回 4.10.3,并执行 gradle clean jacocoTestReport 产生

report 3

因此我们可以得出结论,Gradle 中的某些内容发生了变化。让我们检查一下它的变更日志 - https://docs.gradle.org/5.0/release-notes.html包含一个非常有趣的语句:

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 ...

任务 integrationTest 删除任务 test 收集的数据。让我们尽量不要使用相同的文件:

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

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

现在执行 gradle clean jacocoTestReport 即使是 Gradle 5.4 也会产生

report 4

关于java - Jacoco 代码覆盖率随着迁移到 Java 11 而下降,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55838995/

相关文章:

jenkins - 如何在多个Jenkins作业之间共享jacoco exec文件

java - Maven 构建抛出 java.lang.NoClassDefFoundError

java - 这个错误描述是什么意思?

java - 如何测试 hibernate 通用 dao 模式

Python 接口(interface)模式和单元测试代码覆盖率

gradle - 使用 Wildfly-Arquillian-Gradle-Jacoco 的 EJB 的代码覆盖率

maven - jacoco 检查中的错误 - 参数 'rules' 丢失或无效

java - 从字符串生成 key (com.google.appengine.api.datastore.Key)

java - 如何将模式名称添加到 Spring Data JPA 中的查询注释

golang 生成功能测试的代码覆盖率