【问题标题】:Why do Intellij code coverage and jacoco code coverage show different percentages?为什么 Intellij 代码覆盖率和 jacoco 代码覆盖率显示不同的百分比?
【发布时间】:2019-10-30 14:37:41
【问题描述】:

我在 intellij 中有一个 gradle 项目(java)。我右键单击 intellij 中的项目并运行Run Tests in projectName with coverage,它在右侧创建了一些测试报告。在右手边,我有类似的数字

| Class, %   | Method, %   | Line, %
--------------------------------------
80%(80/100)  50%(100/200)  30%(30/100)

注意:以上数字仅为示例。这些不是真的。

现在我转到命令行并运行 gradlew jacocoTestReport,它为 Method 和 Line 提供了 different set of numbers,但 Class numbers were same。为什么在这种情况下会出现差异?

有没有办法从命令行而不是右键单击来运行 intellij 的代码覆盖率?

我只是想知道 Intellij 是否使用与 jacoco 不同的方法来计算这些数字。但即使在那种情况下,我的假设是只有一种计算方法,对吗?还是 intellij 或 jacoco 不计算具有 Lombok 注释等的类,从而减少最终计数中的方法(getter 和 setter)数量?

【问题讨论】:

  • 分子和分母与方法和线有何不同?您可以轻松检查 IntelliJ 的方法和行。我不知道雅可可。我相信 IntelliJ。我已经看到了由于必须明确告知 SonarCube 等其他代码覆盖工具从统计数据中排除测试类这一事实造成的差异。
  • 我的问题中的数字只是举例。但是发生的事情是 Jacoco 比 Intellij 的代码运行器有更多的方法和更多的行。我在想 Intellij 的代码运行器不计算 lombok 注释等。如果我为具有 2 个字段的类添加 @Getter,则在运行时该类将生成这 2 个方法。也许 Jacoco 正在计算这些课程,而 Intellij 没有?我猜与其他库注释相同。

标签: java gradle intellij-idea code-coverage jacoco


【解决方案1】:

我在一个相关任务中偶然发现了这个问题,虽然它很老,但我认为它可能对某些人来说仍然很有趣。

方法编号

主要问题是intellij覆盖率和jacoco计算数字是否不同,哪种方式是正确的。简要回答:intellij 覆盖摘要使用开发人员直接提供的方法,而 jacoco 在字节码级别上运行并显示在那里找到的方法数量。为了演示这一点,我创建了一个包含四个方法的简单类:

public class Exp {

    private final LinkedList<Integer> vals = new LinkedList<>();

    public void addVal(int v) {
        vals.add(v);
    }

    public List<Integer> doubled() {
        return vals.stream().map(x -> x*2).collect(Collectors.toList());
    }

    public List<Integer> evens() {
        return vals.stream().filter(x -> x%2 == 0).collect(Collectors.toList());
    }

    public static void main(String[] args) {
        Exp t = new Exp();

        t.addVal(1);
        t.addVal(2);
        t.addVal(3);

        System.out.println(t.doubled());
        System.out.println(t.evens());
    }
}

在 intellij 摘要中右侧显示以下值:

所以方法的数量等于示例代码中的方法数量。 Jacoco 报告了七种方法,在报告中可以看到(与 eclipse 2020-09 中的 Emma 插件相同):

这是我们可以在字节码中找到的方法的数量,例如通过使用 javap 反汇编程序命令。这里我们看到两个 lambda 表达式被实现为类的方法,并且还插入了一个标准的构造函数。

C:\_workspace\intellij\Tests\out\production\mod>javap -p Exp.class
Compiled from "Exp.java"
public class Exp {
  private final java.util.LinkedList<java.lang.Integer> vals;
  public Exp();
  public void addVal(int);
  public java.util.List<java.lang.Integer> doubled();
  public java.util.List<java.lang.Integer> evens();
  public static void main(java.lang.String[]);
  private static boolean lambda$evens$1(java.lang.Integer);
  private static java.lang.Integer lambda$doubled$0(java.lang.Integer);
}

让我有点疑惑的是intellij覆盖率报告(Run->Generate Corevage Report)显示了五种方法:

将标准构造函数添加到代码并重新生成报告表明报告包含生成的标准构造函数,但不包含 lambda 表达式。好像有中间计数方法。

至于 intellij 或 jacoco 是否正确的问题,我想说他们都是,这只是定义问题。

行号

在我的测试中,所有报告都显示一致的行号。在上面的示例中,报告了包含可执行代码的 13 行。我对覆盖摘要中的 intellij 行数的印象是它不会一直正确刷新。可能需要进行干净的重建。

【讨论】:

  • 我只想补充一点,文件越大,覆盖率会有所不同,使用 Eclipse 和 Intellij 的开发团队会困惑覆盖率是多少。我有一个 SDK,其中 jacoco/Eclipse 表示覆盖率为 68%,而 IntelliJ 表示覆盖率为 80% 以上。这很糟糕而且很烦人。如果我是对的,Sonar 和 Codecov 之类的工具会解析 jacoco 报告,因此 IntelliJ 覆盖范围毫无用处。
【解决方案2】:

我注意到我使用的@Test 注释来自org.junit.jupiter.api.Test,Jacoco 没有使用它。将导入更改为 import org.junit.Test 修复了我的覆盖率问题。

【讨论】:

  • org.junit.jupiter.api.Test 更改为org.junit.Test 意味着您从JUnit 5 切换到JUnit 4,这不太可能是正确的解决方案。
猜你喜欢
  • 2017-05-31
  • 2019-08-12
  • 2012-06-11
  • 1970-01-01
  • 2014-11-09
  • 2016-11-11
  • 2019-01-02
  • 2012-11-02
  • 2018-05-28
相关资源
最近更新 更多