我在一项相关任务中偶然发现了这个问题,虽然它已经很旧了,但我认为它可能仍然对某些人有趣。
方法数量
主要问题是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摘要中,右侧显示以下数值:
![intellij coverage summary](https://istack.dev59.com/4yp5K.webp)
所以方法的数量等于示例代码中的方法数量。Jacoco报告了七种方法,如报告中所示(与Eclipse 2020-09中的Emma插件相同):
![jacoco test report](https://istack.dev59.com/IBzVn.webp)
这是我们可以在字节码中找到的方法数量,例如通过使用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)显示了五个方法:
![intellij coverage report](https://istack.dev59.com/mzNd3.webp)
添加一个标准构造函数到代码中并重新生成报告后,报告包含了生成的标准构造函数,但不包括lambda表达式。似乎存在一种中间计数方法。
至于Intellij或Jacoco哪个是正确的问题,我会说他们都是正确的,这只是一个定义的问题。
行号:
在我的测试中,所有报告显示的行号都是一致的。在上面的例子中,报告了13行可执行代码。我对Intellij覆盖率摘要中行数的印象是它并不能始终正确地刷新。可能需要进行干净的重建。