Jacoco的Java代码覆盖率。合并从不同应用程序版本收集的执行文件

时间:2019-07-04 16:10:53

标签: java jacoco

我正在尝试建立一个过程,以收集质量检查测试的覆盖率并将此信息汇总到单个报告中。我们有一个庞大的团队,代码更改非常频繁,因此我的主要问题与无法从单个应用程序版本收集覆盖范围有关。根据文档,Jococo应该警告执行数据不匹配的所有类,并将其报告为未涵盖。

[WARN] Execution data for class com/application/package/ClassName does not match.

相关文档:

但是,当我合并从不同版本的应用程序收集到的exec文件时(总共几百万行代码,成千上万个更改的行),Jacoco报告了WARN仅涉及四个类,导致了12行代码。用于报告的JAR文件取自合并的最新版本。

因此,我只是想了解这是可能的,以及我是否可以信任此报告?

2 个答案:

答案 0 :(得分:2)

请考虑以下示例。

版本1包含以下源文件:

src/Example.java

class Example {
  public static void main(String[] args) {
    C.print(A.getPrefix() + B.getSuffix());
  }
}

src/A.java

class A {
  static String getPrefix() {
    return "Hello, ";
  }
}

src/B.java

class B {
  static String getSuffix() {
    return "World";
  }
}

src/C.java

class C {
  static void print(String msg) {
    if ("Hello, World".equals(msg)) {
      System.out.println(msg + "!");
    } else {
      System.out.println(msg);
    }
  }
}

让我们编译并执行版本1:

# javac src/A.java src/B.java src/C.java src/Example.java -d v1

# java \
    -javaagent:jacoco-0.8.4/lib/jacocoagent.jar=destfile=1.exec,sessionid=v1 \
    -cp v1 \
    Example
Hello, World!

版本2:

src/Example.java已修改

class Example {
  public static void main(String[] args) {
    C.print("Hello");
  }
}

src/A.java已修改

class A {
  static String getPrefix() {
    return "";
  }
}

src/B.javasrc/C.java未修改

让我们编译并执行版本2:

# javac src/A.java src/B.java src/C.java src/Example.java -d v2

# java \ 
    -javaagent:jacoco-0.8.4/lib/jacocoagent.jar=destfile=2.exec,sessionid=v2 \
    -cp v2 \
    Example
Hello

请注意,Example.classA.class是不同的,而B.classC.class在两个版本中是相同的:

# diff --report-identical-files v1/Example.class v2/Example.class
Binary files v1/Example.class and v2/Example.class differ

# diff --report-identical-files v1/A.class v2/A.class
Binary files v1/A.class and v2/A.class differ

# diff --report-identical-files v1/B.class v2/B.class
Files v1/B.class and v2/B.class are identical

# diff --report-identical-files v1/C.class v2/C.class
Files v1/C.class and v2/C.class are identical

因此为这些类文件计算了id:

# java -jar jacoco-0.8.4/lib/jacococli.jar classinfo v1
  INST   BRAN   LINE   METH   CXTY   ELEMENT
     8      0      3      2      2   class 0xa170badd641f5a31 Example
     5      0      2      2      2   class 0x45b9146c94e31f23 B
     5      0      2      2      2   class 0xb8f01b5012761c26 A
    16      2      5      2      3   class 0xaf857eca353b9073 C

# java -jar jacoco-0.8.4/lib/jacococli.jar classinfo v2
  INST   BRAN   LINE   METH   CXTY   ELEMENT
     6      0      3      2      2   class 0x5915f0accdd77c81 Example
     5      0      2      2      2   class 0x45b9146c94e31f23 B
     5      0      2      2      2   class 0xa529ea9ab9745b77 A
    16      2      5      2      3   class 0xaf857eca353b9073 C

因此id记录在执行数据中:

# java -jar jacoco-0.8.4/lib/jacococli.jar execinfo 1.exec
[INFO] Loading exec file 1.exec.
CLASS ID         HITS/PROBES   CLASS NAME
Session "v1": Fri Jul 05 20:39:50 CEST 2019 - Fri Jul 05 20:39:50 CEST 2019
b8f01b5012761c26    1 of   2   A
a170badd641f5a31    1 of   2   Example
45b9146c94e31f23    1 of   2   B
af857eca353b9073    3 of   5   C

# java -jar jacoco-0.8.4/lib/jacococli.jar execinfo 2.exec
[INFO] Loading exec file 2.exec.
CLASS ID         HITS/PROBES   CLASS NAME
Session "v2": Fri Jul 05 20:39:50 CEST 2019 - Fri Jul 05 20:39:50 CEST 2019
af857eca353b9073    2 of   5   C
5915f0accdd77c81    1 of   2   Example

让我们合并一下,它将合并具有相同名称和相同ID的类的执行数据:

# java -jar jacoco-0.8.4/lib/jacococli.jar merge 1.exec 2.exec --destfile merged.exec
[INFO] Loading execution data file /private/tmp/j/1.exec.
[INFO] Loading execution data file /private/tmp/j/2.exec.
[INFO] Writing execution data to /private/tmp/j/merged.exec.

# java -jar jacoco-0.8.4/lib/jacococli.jar execinfo merged.exec
[INFO] Loading exec file merged.exec.
CLASS ID         HITS/PROBES   CLASS NAME
Session "v1": Fri Jul 05 20:39:50 CEST 2019 - Fri Jul 05 20:39:50 CEST 2019
Session "v2": Fri Jul 05 20:39:50 CEST 2019 - Fri Jul 05 20:39:50 CEST 2019
b8f01b5012761c26    1 of   2   A
a170badd641f5a31    1 of   2   Example
45b9146c94e31f23    1 of   2   B
af857eca353b9073    4 of   5   C
5915f0accdd77c81    1 of   2   Example

让我们使用合并的执行数据和版本2的类文件生成报告

# java \
    -jar jacoco-0.8.4/lib/jacococli.jar \
    report merged.exec \
    --classfiles v2 \
    --sourcefiles src \
    --html report
[INFO] Loading execution data file /private/tmp/j/merged.exec.
[WARN] Some classes do not match with execution data.
[WARN] For report generation the same class files must be used as at runtime.
[WARN] Execution data for class A does not match.
[INFO] Analyzing 4 classes.

对于src/Example.java,报告将显示有关版本2执行的数据,因为v2/Example.class的ID为5915f0accdd77c81

Example.java

对于src/A.java,报告将不会显示任何内容,因为在merged.exec中没有与v2/A.class的ID相对应的数据,即a529ea9ab9745b77

A.java

带有类似于报告生成过程中警告的消息

A class

对于src/B.java,报告将显示有关版本1执行的数据,因为在merged.exec中,来自1.exec的数据对应于v2/B.class-{{1}的ID }:

B.java

对于45b9146c94e31f23,报告将显示有关两个版本执行情况的组合数据,因为在src/C.java中,来自merged.exec1.exec的数据都与{{ 1}}-2.exec

C.java

从一定意义上来说,以上报告是正确的,因为它完全正确地代表了针对生成报告而提供的各个类文件的两个执行的合并:

  • v2/C.class已执行
  • af857eca353b9073未执行
  • v2/Example.class在版本1中执行
  • v2/A.class中的两个分支均已执行-版本1中的一个分支,版本2中的另一个分支

如果不使用类ID报告,将无法完全检测到

  • B.class将被视为已执行,但从未发生
  • C.class中的
  • 第三行将显示为已执行,但这从未发生

但是,对于所有类别,以上报告并不代表最终版本,因为在最终版本中

  • v2/A.class将永远不会执行
  • A.java中仅一个分支将被执行

答案 1 :(得分:0)

只是决定将以前的答案可视化,以便更好地感知(百分比数字已组成并用于说明目的)。

Merge process