Покрытие Java-кода с помощью Jacoco. Слияние exec-файлов, собранных из разных версий приложения - PullRequest
0 голосов
/ 04 июля 2019

Я пытаюсь установить процесс сбора покрытия тестов QA и объединения этой информации в единый отчет.У нас большая команда, и изменения кода происходят очень часто, поэтому моя главная проблема была связана с невозможностью собрать покрытие из одной версии приложения.В соответствии с документацией Jococo должен предупреждать обо всех классах, где данные исполнения не совпадают, и сообщать о них как о не охваченных.

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

Документы по теме:

Однако, когда я объединил exec-файлы, собранные из разных выпусков приложения (всего миллионы строк кода и тысячи измененных строк), Jacoco сообщил о WARNs только о четырех классах, что привело к12 строк кода.Файлы JAR, использованные для отчета, были взяты из последней версии, которая была частью слияния.

Итак, я просто пытаюсь понять, насколько это возможно, и могу ли я доверять этому отчету или нет?

Ответы [ 2 ]

2 голосов
/ 05 июля 2019

Рассмотрим следующий пример.

Версия 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.java и src/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.class и A.class различны, тогда как B.class и C.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

И поэтому идентификаторы, вычисленные для этих классовфайлы:

# 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

И так, идентификаторы, записанные в данных выполнения:

# 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

Давайте объединим, что объединяет данные выполнения для классов с одинаковым именем и идентификатором:

# 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 равен 5915f0accdd77c81:

Example.java

Для src/A.java отчет ничего не показывает, потому что в merged.exec нет данных, которые соответствуют идентификатору v2/A.class, то есть a529ea9ab9745b77:

A.java

С сообщением, похожим на предупреждение при генерации отчета

A class

Для src/B.java отчет покажет данные о выполнении версии 1, поскольку в merged.exec есть данные из 1.exec, которые соответствуют идентификатору v2/B.class - 45b9146c94e31f23:

B.java

Для src/C.java отчет покажет объединенные данные о выполнении обеих версий, потому что в merged.exec есть данные как из 1.exec, так и 2.exec, которые соответствуют идентификатору v2/C.class - af857eca353b9073:

C.java

Приведенный выше отчет является правильным в том смысле, что он абсолютно правильно представляет слияние двух исполнений в отношении отдельного классафайлы, которые были предоставлены для генерации отчета:

  • v2/Example.class было выполнено
  • v2/A.class не было выполнено
  • B.class быловыполненные в версии 1
  • были выполнены обе ветви в C.class - одна в версии 1, другая в версии 2

Без использования идентификаторов классов отчет будет абсолютно некорректным без возможностиобнаружить это

  • v2/A.class будет считаться выполненным, тогда как этого никогда не было
  • третья строка в A.java будет отображаться как выполненная, тогда как этого никогда не происходило

Однако в отношении всех вместе взятых классов отчет не представляет окончательную версию, потому что в окончательной версии

  • B.class никогда не будет выполняться
  • только одна ветвь вC.class будет исполнено
0 голосов
/ 18 июля 2019

Только что решил визуализировать предыдущий ответ для лучшего восприятия (процентные числа составлены и служат иллюстративным целям).

Merge process

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...