Интеграционное тестовое покрытие в SonarQube от плагина JaCoCo Maven, показывающего 0%

У нас есть многомодульный многоязычный проект maven java с анализом покрытия с помощью jacoco. Основная часть модулей - это бэкэнд (Java-код) с REST API, а наш модуль webapp содержит интерфейс (AngularJS) и Integration-Tests в java. Наш файл Jacoco-IT.exec содержит около 100 Кбайт данных, поэтому мы предполагаем, что некоторые данные Coverage для тестов интеграции могут быть собраны. Тем не менее мы не можем видеть покрытие в SonarQube (используя версии 5.0 и 4.5)

Мы запускаем сборку проекта и запускаем интеграционные тесты с помощью

mvn clean install

и проанализировать данные с помощью

mvn sonar:sonar

Проект настроен как многоязычный, но мы просто анализируем Java-код еще (у нас была конфигурация моноязыков, но не было никакой разницы в результатах, связанных с данными покрытия)

Наш родительский POM:

<properties>
    <hibernate.version>4.2.2.Final</hibernate.version>
    <spring.version>3.2.3.RELEASE</spring.version>
    <resteasy.version>3.0.4.Final</resteasy.version>
    <cucumber.version>1.1.3</cucumber.version>
    <selenium-java.version>2.33.0</selenium-java.version>
    <!-- Sonar -->
    <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
    <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
    <sonar.jacoco.itReportPath>${project.basedir}/../target/jacoco-it.exec</sonar.jacoco.itReportPath>
    <jacoco.dataFile>${project.basedir}/../target/jacoco-it.exec</jacoco.dataFile>
</properties>
<build>
   <plugins>
       <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.7</source>
                <target>1.7</target>
                <debug>true</debug>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>

            <executions>
                <execution>
                    <id>default-prepare-agent</id>
                    <goals>
                        <goal>prepare-agent</goal>
                    </goals>
                </execution>
                <execution>
                    <id>default-prepare-agent-integration</id>
                    <goals>
                        <goal>prepare-agent-integration</goal>
                    </goals>
                </execution>
                <execution>
                    <id>default-report</id>
                    <goals>
                        <goal>report</goal>
                    </goals>
                </execution>
                <execution>
                    <id>default-report-integration</id>
                    <goals>
                        <goal>report-integration</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.16</version>
        </plugin>
    </plugins>
    <pluginManagement>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.7.2.201409121644</version>
            </plugin>
    </pluginMangement>
</build>

Наш POM из webapp с интеграционными испытаниями:

<properties>
    <sonar.sources>src/main</sonar.sources>
</properties>
<build>
    <finalName>web</finalName>
    <plugins>
        <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <version>8.1.7.v20120910</version>
        <configuration>...</configuration>
        <executions>...</executions>
    </plugin>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <configuration>
                <!-- The destination file for the code coverage report has to be set to the same value
                in the parent pom and in each module pom. Then JaCoCo will add up information in
                the same report, so that, it will give the cross-module code coverage. -->
                <destFile>${project.basedir}/../target/jacoco-it.exec</destFile>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.16</version>
            <executions>
                <execution>
                    <id>default</id>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Как вы можете видеть в нашем родительском POM, мы сконфигурировали itReportPath в том же каталоге для всех модулей. Поэтому, когда Sonar анализирует все модули, он всегда считывает одни и те же данные о покрытии и должен выровнять их с информацией об отладке из двоичных файлов текущего модуля. Во время фазы анализа maven (mvn sonar: sonar) мы получаем сообщения, в которых мы не уверены, что они являются проблемой:

для всех модулей java мы получаем следующие строки:

    [INFO] [17:30:42.992] Sensor SurefireSensor...
    [INFO] [17:30:42.992] parsing \git\airport-core\rest\target\surefire-reports
    [INFO] [17:30:43.009] Sensor SurefireSensor done: 17 ms
    [INFO] [17:30:43.009] Sensor JaCoCoItSensor...
    [INFO] [17:30:43.010] Analysing \git\airport-core\rest\..\target\jacoco-it.exec
    [INFO] [17:30:43.018] No information about coverage per test.
    [INFO] [17:30:43.018] Sensor JaCoCoItSensor done: 9 ms
    [INFO] [17:30:43.018] Sensor JaCoCoOverallSensor...
    [INFO] [17:30:43.027] Analysing \git\airport-core\rest\target\sonar\jacoco-overall.exec
    [INFO] [17:30:43.046] No information about coverage per test.
    [INFO] [17:30:43.046] Sensor JaCoCoOverallSensor done: 28 ms

"Нет информации о покрытии за тест". проблема? Хорошо, мы не знаем, какой тест вызвал покрытие, но мы должны получить другое значение в SonarQube, чем 0%

и для нашего модуля webapp, который не содержит каких-либо источников/классов java, кроме самих тестовых источников интеграции, мы получаем следующие строки:

    [INFO] [17:30:48.370] Sensor JaCoCoItSensor...
    [INFO] [17:30:48.370] No JaCoCo analysis of project coverage can be done since there is no class files.
    [INFO] [17:30:48.370] Sensor JaCoCoItSensor done: 0 ms

Это не должно быть проблемой, так как в этом модуле нет классов. Правильно ли это наблюдение?

В основной части наша конфигурация основывается на официальной демо-конфигурации SonarCube (https://github.com/SonarSource/sonar-examples/tree/master/projects/languages/java/code-coverage/combined%20ut-it/combined-ut-it-multimodule-maven-jacoco), мы просто добавили цель "подготовка-агент-интеграция". И, конечно, изменил его на многоязычный проект.

Мы обнаружили много информации, которая была лишена информации в Интернете (настройки argLine и т.д.), которая ничего не меняла для нас.

Ссылки на документацию и руководства, которые мы использовали:

Ответ 1

После очень долгого сражения с Якоко и Мэвеном только таким образом он работает для меня:

  • Создать профиль в pom.xml

    <profile>
      <id>coverage-per-test</id>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.19.1</version>
            <configuration>
             <!-- disable parallel execution so that JaCoCo listener can properly work -->
              <parallel>none</parallel>
              <perCoreThreadCount>false</perCoreThreadCount>
              <forkCount>1</forkCount>
              <properties>
                <property>
                  <name>listener</name>
                  <value>org.sonar.java.jacoco.JUnitListener</value>
                </property>
              </properties>
            </configuration>
          </plugin>
        </plugins>
      </build>
    
      <dependencies>
        <dependency>
          <groupId>org.sonarsource.java</groupId>
          <artifactId>sonar-jacoco-listeners</artifactId>
          <version>3.10</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </profile>
    
  • Обновите плагин maven surefire до последней версии

  • Выполнить команды:

    mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent install -Pcoverage-per-test -Dmaven.test.failure.ignore=true
    
    mvn sonar:sonar
    

Аналогично описанию в примере github сонара

Ответ 2

У меня был такой же опыт, когда я настраивал JaCoCo для Jersey. В результате я использовал метод бисекции, чтобы выяснить, какие модули приводят к тому, что покрытие кода для всего проекта опустится до 0%.

Если я правильно его помню, самым большим сюрпризом было maven-shade-plugin, которое каким-то образом исказило связь между собранным покрытием и расположением классов, из-за чего Sonar показывал 0% -ный охват кода. Я закончил отключать его выполнение, привязывая его к фазе none, чтобы исправить его (см. this commit).

В качестве примера, это способ расширения pom.xml подмодуля, чтобы иметь рабочий сонар (предполагая, что сонар выполняется с профилем sonar maven).

<profile>
    <id>sonar</id>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <!-- disable parallel execution so that JaCoCo listener can properly work -->
                    <parallel>none</parallel>
                    <perCoreThreadCount>false</perCoreThreadCount>
                    <forkCount>1</forkCount>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-shade-plugin</artifactId>
                <executions>
                    <execution>
                        <id>shade-archive</id>
                        <phase>none</phase>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-debug-all</artifactId>
            <optional>false</optional>
        </dependency>
    </dependencies>
</profile>

Ответ 3

Учитывая другие ответы, я хочу добавить одну вещь, которая важна для показа тестового покрытия на Sonar:

  • вам нужно создать проект, прежде чем ожидать отображения покрытия: mvn clean install
  • вам нужно построить без -DskipTests
  • вам нужно сохранить правильные конфигурации для плагина, которые запускают тесты (surefire, failafe,... plugin) - покрытие будет отображаться с учетом только тех тестов, которые включены в конфигурации плагинов на <includes> или аналогичные конфигурации.

Ответ 4

Я использую JUnit, и в моем случае проблема была связана с наличием зависимости TestNG в моем pom.xml в дополнение к JUnit. После удаления этой ненужной зависимости все начало работать, как ожидалось.