Jak skonfigurować wielomodułowy Maven + Sonar + JaCoCo, aby uzyskać połączony raport pokrycia?

128

Szukałem tego w Internecie. Jest wiele pół odpowiedzi tam, aby zrobić z właściwości takich jak Maven ${sonar.jacoco.reportPath}, lub org.jacoco:jacoco-maven-plugin:prepare-agentczy ustawienie maven-surefire-plugin argLinez -javaagent.

W pewnym sensie żadna z tych odpowiedzi, samodzielnie lub w połączeniu, nie daje tego, czego szukam: Raport pokrycia, który pokazuje, że klasa jest objęta, jeśli jest używana w testach wyżej na stosie, takich jak używane encje przez DAO, mimo że nie był w pełni objęty testami we własnym module.

Czy jest gdzieś ostateczna konfiguracja, aby to osiągnąć?

Stewart
źródło

Odpowiedzi:

164

Byłem w takiej samej sytuacji jak Ty, pół odpowiedzi rozproszone po całym Internecie były dość irytujące, ponieważ wydawało się, że wiele osób ma ten sam problem, ale nikt nie mógł się martwić, aby w pełni wyjaśnić, jak go rozwiązali.

Dokumentacja Sonar odnosi się do projektu GitHub z przykładami, które są pomocne. Aby rozwiązać ten problem, zastosowałem logikę testów integracyjnych do zwykłych testów jednostkowych (chociaż prawidłowe testy jednostkowe powinny być specyficzne dla podmodułu, nie zawsze tak jest).

W nadrzędnym pom.xml dodaj następujące właściwości:

<properties>
    <!-- Sonar -->
    <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
    <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
    <sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
    <sonar.language>java</sonar.language>
</properties>

Spowoduje to, że Sonar pobierze raporty z testów jednostkowych dla wszystkich modułów podrzędnych w tym samym miejscu (folder docelowy w projekcie nadrzędnym). Nakazuje również Sonarowi ponowne wykorzystanie raportów wykonanych ręcznie zamiast tworzenia własnych. Musimy tylko sprawić, by jacoco-maven-plugin działał dla wszystkich podmodułów, umieszczając to w macierzystym pom, wewnątrz kompilacji / wtyczek:

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.6.0.201210061924</version>
    <configuration>
        <destFile>${sonar.jacoco.reportPath}</destFile>
        <append>true</append>
    </configuration>
    <executions>
        <execution>
            <id>agent</id>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
    </executions>
</plugin>

destFileumieszcza plik raportu w miejscu, w którym Sonar będzie go szukał i appendsprawia, że ​​jest on dołączany do pliku zamiast go nadpisywać. Spowoduje to połączenie wszystkich raportów JaCoCo dla wszystkich podmodułów w tym samym pliku.

Sonar sprawdzi ten plik dla każdego modułu podrzędnego, ponieważ wskazaliśmy mu na to powyżej, dając nam połączone wyniki testów jednostkowych dla plików wielomodułowych w Sonar.

mpontes
źródło
Cudowny! To zadziałało. Wreszcie! Wydaje mi się, że magia, której brakowało w życiu, była <append> prawda </append>
Stewart
To działa! Musiałem zrobić nowy mvn packageprzed uruchomieniem, mvn sonar:sonaraby wygenerować nową ścieżkę raportu.
thomasa88,
2
Zgodnie z przykładem, należy użyć właściwości „sonar.jacoco.itReportPath”, aby uzyskać scalone wyniki w „ogólne pokrycie kodu”. Zaktualizuj odpowiedź.
Yves Martin
4
„sonar.dynamicAnalysis” również jest przestarzała: docs.sonarqube.org/display/SONAR/Release+4.3+Upgrade+Notes
Yves Martin
3
Zaktualizowany link: docs.sonarqube.org/display/SONARQUBE53/…
Lonzak
23

FAQ

Pytania z góry głowy od tego czasu oszalałem na punkcie jacoco.

Mój serwer aplikacji (jBoss, Glassfish ..) znajduje się w Iraku, Syrii, cokolwiek ... Czy jest możliwe uzyskanie pokrycia wielomodułowego podczas przeprowadzania na nim testów integracyjnych? Jenkins i Sonar również znajdują się na różnych serwerach.

Tak. Musisz użyć agenta jacoco, który działa w trybie output=tcpserver, jacoco ant lib. Zasadniczo dwie jarsekundy. To da ci 99% sukcesu.

Jak działa agent jacoco?

Dołączasz ciąg

-javaagent:[your_path]/jacocoagent.jar=destfile=/jacoco.exec,output=tcpserver,address=*

do serwera aplikacji JAVA_OPTS i zrestartuj go. W tym ciągu wystarczy tylko [your_path]zastąpić ścieżkę do jacocoagent.jar, przechowywaną (przechowuj ją!) Na maszynie wirtualnej, na której działa serwer aplikacji. Od tego czasu uruchomisz serwer aplikacji, wszystkie wdrożone aplikacje będą dynamicznie monitorowane, a ich aktywność (czyli użycie kodu) będzie gotowa do uzyskania w formacie jacocos .exec na żądanie tcl.

Czy mogę zresetować agenta jacoco, aby zaczął zbierać dane wykonania dopiero od czasu rozpoczęcia mojego testu?

Tak, w tym celu potrzebujesz jacocoant.jar i skryptu budującego mrówka znajdującego się w obszarze roboczym jenkins.

Więc zasadniczo to, czego potrzebuję z http://www.eclemma.org/jacoco/, to jacocoant.jar znajdujący się w moim obszarze roboczym jenkins i jacocoagent.jar znajdujący się na mojej maszynie wirtualnej serwera aplikacji?

Zgadza się.

Nie chcę używać mrówka, słyszałem, że wtyczka jacoco maven też potrafi wszystko.

To nie w porządku, wtyczka jacoco maven może zbierać dane z testów jednostkowych i niektóre dane z testów integracji (patrz Arquillian Jacoco ), ale jeśli masz na przykład spokojne testy jako oddzielną kompilację w jenkins i chcesz pokazać pokrycie wielu modułów, mogę Nie widzę, jak wtyczka Maven może ci pomóc.

Co dokładnie wytwarza agent jacoco?

Tylko dane pokrycia w .execformacie. Sonar może to odczytać.

Czy jacoco musi wiedzieć, gdzie znajdują się moje klasy Java?

Nie, sonar tak, ale nie jacoco. Kiedy idziesz mvn sonar:sonarna zajęcia, w grę wchodzi.

A co ze skryptem mrówek?

Musi być prezentowany w Twoim obszarze roboczym Jenkinsa. Mój skrypt mrówki, nazwałem go jacoco.xmltak:

<project name="Jacoco library to collect code coverage remotely" xmlns:jacoco="antlib:org.jacoco.ant">
    <property name="jacoco.port" value="6300"/>
    <property name="jacocoReportFile" location="${workspace}/it-jacoco.exec"/>

    <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
        <classpath path="${workspace}/tools/jacoco/jacocoant.jar"/>
    </taskdef>

    <target name="jacocoReport">
            <jacoco:dump address="${jacoco.host}" port="${jacoco.port}" dump="true" reset="true" destfile="${jacocoReportFile}" append="false"/>
    </target>

    <target name="jacocoReset">
            <jacoco:dump address="${jacoco.host}" port="${jacoco.port}" reset="true" destfile="${jacocoReportFile}" append="false"/>
        <delete file="${jacocoReportFile}"/>
    </target>
</project>

Dwa obowiązkowe parametry, które należy przekazać podczas wywoływania tego skryptu, -Dworkspace=$WORKSPACE używają go do wskazania obszaru roboczego Jenkinsa i -Djacoco.host=yourappserver.comhosta bezhttp://

Zauważ też, że umieściłem mój jacocoant.jarw $ {workspace} /tools/jacoco/jacocoant.jar

Co mam teraz zrobić?

Czy serwer aplikacji został uruchomiony z plikiem jacocoagent.jar?

Czy umieściłeś ant script i jacocoant.jar w swoim obszarze roboczym Jenkins?

Jeśli tak, ostatnim krokiem jest skonfigurowanie kompilacji Jenkinsa. Oto strategia:

  1. Wywołaj cel mrówki, jacocoResetaby zresetować wszystkie zebrane wcześniej dane.
  2. Przeprowadź testy
  3. Wywołaj cel mrówki, jacocoReportaby uzyskać raport

Jeśli wszystko jest w porządku, zobaczysz it-jacoco.execw obszarze roboczym kompilacji.

Spójrz na zrzut ekranu, mam również antzainstalowany w moim obszarze roboczym w $WORKSPACE/tools/antdir, ale możesz użyć takiego, który jest zainstalowany w twoich jenkinsach.

wprowadź opis obrazu tutaj

Jak przesłać ten raport do sonaru?

Maven sonar:sonarwykona zadanie (nie zapomnij go skonfigurować), wskaże mu główny pom.xml, aby przeszedł przez wszystkie moduły. Użyj sonar.jacoco.itReportPath=$WORKSPACE/it-jacoco.execparametru, aby wskazać sonarowi, gdzie znajduje się raport z testu integracji. Za każdym razem, gdy przeanalizuje nowe klasy modułów, będzie szukał informacji o pokryciu w it-jacoco.exec.

Mam już jacoco.exec w moim katalogu docelowym, sonar mvn: sonar go ignoruje / usuwa

Domyślnie mvn sonar:sonarrobi cleani usuwa katalog docelowy, użyj, sonar.dynamicAnalysis=reuseReportsaby tego uniknąć.

ZuzEL
źródło
20

NOWA SPOSÓB OD WERSJI 0.7.7

Od wersji 0.7.7 istnieje nowy sposób tworzenia raportu zbiorczego:

Tworzysz osobny projekt „raportu”, który zbiera wszystkie niezbędne raporty (każdy cel w projekcie agregatora jest wykonywany przed jego modułami, dlatego nie można go użyć).

aggregator pom
  |- parent pom
  |- module a
  |- module b
  |- report module 

W korzeń pom wygląda następująco (nie zapomnij dodać nowy moduł raportu pod moduły):

<build>
<plugins>
  <plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.7.8</version>
    <executions>
      <execution>
        <id>prepare-agent</id>
        <goals>
          <goal>prepare-agent</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
</plugins>

Poms z każdego modułu podrzędnego w ogóle nie musi być zmieniany. Pom z modułu raportu wygląda następująco:

<!-- Add all sub modules as dependencies here -->
<dependencies>
  <dependency>
    <module a>
  </dependency>
  <dependency>
    <module b>
  </dependency>
 ...

  <build>
    <plugins>
      <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.7.8</version>
        <executions>
          <execution>
            <id>report-aggregate</id>
            <phase>verify</phase>
            <goals>
              <goal>report-aggregate</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

Pełen przykład można znaleźć tutaj .

Lonzak
źródło
3
To działa. Raport zbiorczy przedstawia skumulowane pokrycie kodu dla wszystkich modułów. Czy kiedykolwiek próbowałeś wyświetlić ten zbiorczy raport w Sonar? Użyłem sonar-qube do odczytu jacoco.exec dla poszczególnych raportów, ale z tym zagregowanym raportem nie widzę zagregowanego jacoco.exec w module raportów.
Swetha V
@SwethaV Jakiś sukces w tym? Jesteśmy w tej samej sytuacji i musimy znaleźć sposób na wygenerowanie zagregowanego exec :)
Vinky
Używamy kostki sonaru w wersji 6.X, która ma własną stronę z badaniami, więc nie potrzebuję tam jacoco. W przypadku starszej wersji zainstalowaliśmy wtyczkę cobertura, która również zapewniała tę funkcjonalność ...
Lonzak
11

Opublikuję moje rozwiązanie, ponieważ różni się ono nieznacznie od innych, a także zajęło mi cały dzień, aby uzyskać dobre wyniki, z pomocą istniejących odpowiedzi.

W przypadku wielomodułowego projektu Maven:

ROOT
|--WAR
|--LIB-1
|--LIB-2
|--TEST

Tam, gdzie WARprojekt jest główną aplikacją internetową, LIB1 i 2 to dodatkowe moduły, od których WARzależą i od TESTktórych odbywają się testy integracji. TESTuruchamia osadzoną instancję Tomcat (nie przez wtyczkę Tomcat) i uruchamia WARprojekt i testuje je za pomocą zestawu testów JUnit. WARI LIBprojekty zarówno mają własne testy jednostkowe.

Rezultatem tego wszystkiego jest oddzielenie pokrycia integracji i testów jednostkowych i możliwość ich rozróżnienia w SonarQube.

ROOT pom.xml

<!-- Sonar properties-->
<sonar.jacoco.itReportPath>${project.basedir}/../target/jacoco-it.exec</sonar.jacoco.itReportPath>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.language>java</sonar.language>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>

<!-- build/plugins (not build/pluginManagement/plugins!) -->
<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.7.6.201602180812</version>
    <executions>
        <execution>
            <id>agent-for-ut</id>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
            <configuration>
                <append>true</append>
                <destFile>${sonar.jacoco.reportPath}</destFile>
            </configuration>
        </execution>
        <execution>
            <id>agent-for-it</id>
            <goals>
                <goal>prepare-agent-integration</goal>
            </goals>
            <configuration>
                <append>true</append>
                <destFile>${sonar.jacoco.itReportPath}</destFile>
            </configuration>
        </execution>
    </executions>
</plugin>

WAR, LIB i TEST pom.xmlodziedziczy wykonanie wtyczki JaCoCo.

TEST pom.xml

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.19.1</version>
    <executions>
        <execution>
            <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
            </goals>
            <configuration>
                <skipTests>${skip.tests}</skipTests>
                <argLine>${argLine} -Duser.timezone=UTC -Xms256m -Xmx256m</argLine>
                <includes>
                    <includes>**/*Test*</includes>
                </includes>
            </configuration>
        </execution>
    </executions>
</plugin>

Zauważyłem również, że wpis na blogu Petri Kainulainens „Tworzenie raportów pokrycia kodu dla testów jednostkowych i testów integracji z wtyczką JaCoCo Maven” jest wartościowy dla strony konfiguracji JaCoCo.

markdsievers
źródło
Muszę zaktualizować ten post na pewnym etapie, ponieważ w rzeczywistości jest on trochę nieoptymalny. agent-for-itjest niezbędny tylko podczas uruchamiania testów w TESTmodule, ale w obecnej konfiguracji jest on uruchamiany dla każdego innego modułu, gdzie nie ma wartości. Poprawa polegałaby na agent-for-uturuchomieniu wszystkich innych modułów i agent-for-ittylko uruchomieniu TEST.
markdsievers
7

Jest na to sposób. Magia polega na stworzeniu połączonego pliku jacoco.exec. Dzięki maven 3.3.1 można to łatwo osiągnąć. Tutaj mój profil:

<profile>
    <id>runSonar</id>
    <activation>
        <property>
            <name>runSonar</name>
            <value>true</value>
        </property>
    </activation>
    <properties>
        <sonar.language>java</sonar.language>
        <sonar.host.url>http://sonar.url</sonar.host.url>
        <sonar.login>tokenX</sonar.login>
        <sonar.jacoco.reportMissing.force.zero>true</sonar.jacoco.reportMissing.force.zero>
        <sonar.jacoco.reportPath>${jacoco.destFile}</sonar.jacoco.reportPath>
        <jacoco.destFile>${maven.multiModuleProjectDirectory}/target/jacoco_analysis/jacoco.exec</jacoco.destFile>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>default-prepare-agent</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <append>true</append>
                            <destFile>${jacoco.destFile}</destFile>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.sonarsource.scanner.maven</groupId>
                    <artifactId>sonar-maven-plugin</artifactId>
                    <version>3.2</version>
                </plugin>
                <plugin>
                    <groupId>org.jacoco</groupId>
                    <artifactId>jacoco-maven-plugin</artifactId>
                    <version>0.7.8</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</profile>

Jeśli dodasz ten profil do swojego rodzica i zadzwonisz mvn clean install sonar:sonar -DrunSonar, otrzymasz pełne ubezpieczenie.

Oto magia maven.multiModuleProjectDirectory. Ten folder jest zawsze folderem, w którym rozpocząłeś kompilację mavena.

Sven Oppermann
źródło
To zadziałało dla mnie, po przejściu przez wiele innych rozwiązań.
Jimson Kannanthara James
Jedynym problemem było to, że musiałem uruchomić sonar z poleceniem, z mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.4.0.905:sonar -DrunSonarpowodu A required class was missing while executing org.sonarsource.scanner.maven:sonar-maven-plugin:3.0.1:sonar: org/sonar/batch/bootstrapper/IssueListenerbłędu.
Jimson Kannanthara James
1
Nie używaj tej magii. Podana właściwość jest szczegółem implementacyjnym i nie można na niej polegać. - Zespół programistów Maven
Michael-O
6

Konfiguracja, której używam w pom na poziomie rodzica, gdzie mam oddzielne fazy testów jednostkowych i integracyjnych.

Konfiguruję następujące właściwości w nadrzędnych właściwościach POM

    <maven.surefire.report.plugin>2.19.1</maven.surefire.report.plugin>
    <jacoco.plugin.version>0.7.6.201602180812</jacoco.plugin.version>
    <jacoco.check.lineRatio>0.52</jacoco.check.lineRatio>
    <jacoco.check.branchRatio>0.40</jacoco.check.branchRatio>
    <jacoco.check.complexityMax>15</jacoco.check.complexityMax>
    <jacoco.skip>false</jacoco.skip>
    <jacoco.excludePattern/>
    <jacoco.destfile>${project.basedir}/../target/coverage-reports/jacoco.exec</jacoco.destfile>

    <sonar.language>java</sonar.language>
    <sonar.exclusions>**/generated-sources/**/*</sonar.exclusions>
    <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
    <sonar.coverage.exclusions>${jacoco.excludePattern}</sonar.coverage.exclusions>
    <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
    <sonar.jacoco.reportPath>${project.basedir}/../target/coverage-reports</sonar.jacoco.reportPath>

    <skip.surefire.tests>${skipTests}</skip.surefire.tests>
    <skip.failsafe.tests>${skipTests}</skip.failsafe.tests>

Umieszczam definicje wtyczek w zarządzaniu wtyczkami.

Zauważ, że zdefiniowałem właściwość dla argumentów surefire (surefireArgLine) i failafe (failedafeArgLine), aby umożliwić jacoco skonfigurowanie javaagent do uruchamiania z każdym testem.

W ramach zarządzania wtyczkami

  <build>
     <pluginManagment>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <fork>true</fork>
                    <meminitial>1024m</meminitial>
                    <maxmem>1024m</maxmem>
                    <compilerArgument>-g</compilerArgument>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.19.1</version>
                <configuration>
                    <forkCount>4</forkCount>
                    <reuseForks>false</reuseForks>
                    <argLine>-Xmx2048m ${surefireArgLine}</argLine>
                    <includes>
                        <include>**/*Test.java</include>
                    </includes>
                    <excludes>
                        <exclude>**/*IT.java</exclude>
                    </excludes>
                    <skip>${skip.surefire.tests}</skip>
                </configuration>
            </plugin>
            <plugin>
                <!-- For integration test separation -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>2.19.1</version>
                <dependencies>
                    <dependency>
                        <groupId>org.apache.maven.surefire</groupId>
                        <artifactId>surefire-junit47</artifactId>
                        <version>2.19.1</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <forkCount>4</forkCount>
                    <reuseForks>false</reuseForks>
                    <argLine>${failsafeArgLine}</argLine>
                    <includes>
                        <include>**/*IT.java</include>
                    </includes>
                    <skip>${skip.failsafe.tests}</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>integration-test</id>
                        <goals>
                            <goal>integration-test</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>verify</id>
                        <goals>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <!-- Code Coverage -->
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco.plugin.version}</version>
                <configuration>
                    <haltOnFailure>true</haltOnFailure>
                    <excludes>
                        <exclude>**/*.mar</exclude>
                        <exclude>${jacoco.excludePattern}</exclude>
                    </excludes>
                    <rules>
                        <rule>
                            <element>BUNDLE</element>
                            <limits>
                                <limit>
                                    <counter>LINE</counter>
                                    <value>COVEREDRATIO</value>
                                    <minimum>${jacoco.check.lineRatio}</minimum>
                                </limit>
                                <limit>
                                    <counter>BRANCH</counter>
                                    <value>COVEREDRATIO</value>
                                    <minimum>${jacoco.check.branchRatio}</minimum>
                                </limit>
                            </limits>
                        </rule>
                        <rule>
                            <element>METHOD</element>
                            <limits>
                                <limit>
                                    <counter>COMPLEXITY</counter>
                                    <value>TOTALCOUNT</value>
                                    <maximum>${jacoco.check.complexityMax}</maximum>
                                </limit>
                            </limits>
                        </rule>
                    </rules>
                </configuration>
                <executions>
                    <execution>
                        <id>pre-unit-test</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <destFile>${jacoco.destfile}</destFile>
                            <append>true</append>
                            <propertyName>surefireArgLine</propertyName>
                        </configuration>
                    </execution>
                    <execution>
                        <id>post-unit-test</id>
                        <phase>test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                        <configuration>
                            <dataFile>${jacoco.destfile}</dataFile>
                            <outputDirectory>${sonar.jacoco.reportPath}</outputDirectory>
                            <skip>${skip.surefire.tests}</skip>
                        </configuration>
                    </execution>
                    <execution>
                        <id>pre-integration-test</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>prepare-agent-integration</goal>
                        </goals>
                        <configuration>
                            <destFile>${jacoco.destfile}</destFile>
                            <append>true</append>
                            <propertyName>failsafeArgLine</propertyName>
                        </configuration>
                    </execution>
                    <execution>
                        <id>post-integration-test</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>report-integration</goal>
                        </goals>
                        <configuration>
                            <dataFile>${jacoco.destfile}</dataFile>
                            <outputDirectory>${sonar.jacoco.reportPath}</outputDirectory>
                            <skip>${skip.failsafe.tests}</skip>
                        </configuration>
                    </execution>
                    <!-- Disabled until such time as code quality stops this tripping
                    <execution>
                        <id>default-check</id>
                        <goals>
                            <goal>check</goal>
                        </goals>
                        <configuration>
                            <dataFile>${jacoco.destfile}</dataFile>
                        </configuration>
                    </execution>
                    -->
                </executions>
            </plugin>
            ...

I w sekcji kompilacji

 <build>
     <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
        </plugin>

        <plugin>
            <!-- for unit test execution -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
        </plugin>
        <plugin>
            <!-- For integration test separation -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
        </plugin>
        <plugin>
            <!-- For code coverage -->
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
        </plugin>
        ....

Oraz w sekcji raportowania

    <reporting>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-report-plugin</artifactId>
            <version>${maven.surefire.report.plugin}</version>
            <configuration>
                <showSuccess>false</showSuccess>
                <alwaysGenerateFailsafeReport>true</alwaysGenerateFailsafeReport>
                <alwaysGenerateSurefireReport>true</alwaysGenerateSurefireReport>
                <aggregate>true</aggregate>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>${jacoco.plugin.version}</version>
            <configuration>
                <excludes>
                    <exclude>**/*.mar</exclude>
                    <exclude>${jacoco.excludePattern}</exclude>
                </excludes>
            </configuration>
        </plugin>
     </plugins>
  </reporting>
sweetfa
źródło
1
Widzę, że masz <append>true</append>konfigurację w prepare-agentsekcjach ...
Stewart
Nacisk. Przeczytaj mój komentarz do innej odpowiedzi. To był dla mnie brakujący istotny składnik, którego nie znaleziono w innych dokumentach.
Stewart
czy masz do tego link na githubie? Chcę zrobić dokładnie podobne konfiguracje
Rohit Kasat
@Rhit - nie, nie mam, przynajmniej nie w publicznym repozytorium.
sweetfa
Działa to bardzo dobrze z Sonar Qube w wersji 6.5 (kompilacja 27846) ...: D Pokrycie kodu będzie poprawnie wyświetlane.
udoline
4

Znalazłem inne rozwiązanie dla nowych wersji Sonara, w którym format raportu binarnego JaCoCo (* .exec) został wycofany, a preferowanym formatem jest XML (SonarJava 5.12 i nowsze). Rozwiązanie jest bardzo proste i podobne do poprzedniego rozwiązania z raportami * .exec w katalogu nadrzędnym z tego tematu: https://stackoverflow.com/a/15535970/4448263 .

Zakładając, że nasza struktura projektu to:

moduleC - aggregate project's pom
  |- moduleA - some classes without tests
  |- moduleB - some classes depending from moduleA and tests for classes in both modules: moduleA and moduleB

Potrzebujesz następującej konfiguracji wtyczki maven build w zbiorczym pom projektu:

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.5</version>
    <executions>
        <execution>
            <id>prepare-and-report</id>
            <goals>
                <goal>prepare-agent</goal>
                <goal>report</goal>
            </goals>
        </execution>
        <execution>
            <id>report-aggregate</id>
            <phase>verify</phase>
            <goals>
                <goal>report-aggregate</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.basedir}/../target/site/jacoco-aggregate</outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>

Następnie zbuduj projekt za pomocą maven:

mvn clean verify

W przypadku Sonara należy ustawić właściwość w administracyjnym interfejsie użytkownika:

sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml,../target/site/jacoco-aggregate/jacoco.xml

lub używając linii poleceń:

mvn sonar:sonar -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml,../target/site/jacoco-aggregate/jacoco.xml

Opis

To tworzy raporty binarne dla każdego modułu w domyślnych katalogach: target/jacoco.exec. Następnie tworzy raporty w formacie XML dla każdego modułu w domyślnych katalogach: target/site/jacoco/jacoco.xml. Następnie tworzy raport zbiorczy dla każdego modułu w katalogu niestandardowym, ${project.basedir}/../target/site/jacoco-aggregate/który jest powiązany z katalogiem nadrzędnym dla każdego modułu. Dla modułu A i modułuB będzie to wspólna ścieżkamoduleC/target/site/jacoco-aggregate/ .

Ponieważ moduł B zależy od modułu A, moduł B zostanie zbudowany jako ostatni, a jego raport zostanie wykorzystany jako zbiorczy raport pokrycia w Sonar dla obu modułów A i B.

Oprócz raportu zbiorczego potrzebujemy zwykłego raportu modułu, ponieważ raporty zbiorcze JaCoCo zawierają dane pokrycia tylko dla zależności.

Razem te dwa typy raportów zapewniają pełne dane pokrycia dla Sonar.

Jest jedno małe ograniczenie: powinieneś być w stanie napisać raport w katalogu nadrzędnym projektu (powinieneś mieć uprawnienia). Lub możesz ustawić właściwość jacoco.skip=truew pom.xml projektu głównego (moduleC) oraz jacoco.skip=falsew modułach z klasami i testami (moduleA i moduleB).

keddok
źródło
2
    <sonar.language>java</sonar.language>
    <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
    <sonar.jacoco.reportPath>${user.dir}/target/jacoco.exec</sonar.jacoco.reportPath>
    <sonar.jacoco.itReportPath>${user.dir}/target/jacoco-it.exec</sonar.jacoco.itReportPath>
    <sonar.exclusions>
        file:**/target/generated-sources/**,
        file:**/target/generated-test-sources/**,
        file:**/target/test-classes/**,
        file:**/model/*.java,
        file:**/*Config.java,
        file:**/*App.java
    </sonar.exclusions>

            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.7.9</version>
                <executions>
                    <execution>
                        <id>default-prepare-agent</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <destFile>${sonar.jacoco.reportPath}</destFile>
                            <append>true</append>
                            <propertyName>surefire.argLine</propertyName>
                        </configuration>
                    </execution>
                    <execution>
                        <id>default-prepare-agent-integration</id>
                        <goals>
                            <goal>prepare-agent-integration</goal>
                        </goals>
                        <configuration>
                            <destFile>${sonar.jacoco.itReportPath}</destFile>
                            <append>true</append>
                            <propertyName>failsafe.argLine</propertyName>
                        </configuration>
                    </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>             
Mikrofon
źródło
2

Jak sonary sonar.jacoco.reportPath, sonar.jacoco.itReportPatha sonar.jacoco.reportPathswszystkie zostały przestarzałe , należy użyćsonar.coverage.jacoco.xmlReportPaths teraz. Ma to również wpływ, jeśli chcesz skonfigurować projekt wielomodułowy Maven z Sonar i Jacoco.

Jak zauważył @Lonzak , od Sonar 0.7.7 możesz używać celu agregacji raportu Sonary. Po prostu umieść w swoim rodzicu pom następującą zależność:

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.5</version>
    <executions>
        <execution>
            <id>report</id>
            <goals>
                <goal>report-aggregate</goal>
            </goals>
            <phase>verify</phase>
        </execution>
    </executions>
</plugin>

Ponieważ obecne wersje wtyczki jacoco-maven są kompatybilne z raportami xml, utworzy to dla każdego modułu w jego własnym folderze docelowym folder site / jacoco-zagregowany zawierający jacoco.xmlplik.

Aby Sonar połączył wszystkie moduły, użyj następującego polecenia:

mvn -Dsonar.coverage.jacoco.xmlReportPaths=full-path-to-module1/target/site/jacoco-aggregate/jacoco.xml,module2...,module3... clean verify sonar:sonar

Aby moja odpowiedź była krótka i precyzyjna, nie wspomniałem o zależnościach maven-surefire-plugini maven-failsafe-plugin. Możesz je po prostu dodać bez żadnej innej konfiguracji:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.22.2</version>
    <executions>
        <execution>
        <id>integration-test</id>
            <goals>
                <goal>integration-test</goal>
            </goals>
        </execution>
    </executions>
</plugin>
Jacob van Lingen
źródło
1

Możesz wywołać zadanie mrówki o nazwie scalanie on maven, aby umieścić wszystkie pliki pokrycia (* .exec) razem w tym samym pliku.

Jeśli uruchamiasz testy jednostkowe, użyj pakietu przygotowania fazy , jeśli uruchamiasz test integracji, użyj testu po integracji .

Ta strona zawiera przykład, jak wywołać zadanie jacoco ant w projekcie maven

Możesz użyć tego scalonego pliku na sonarze.

Andre Piantino
źródło
0

aby mieć testowanie jednostkowe ORAZ testowanie integracji, możesz użyć maven-surefire-plugin i maven-failafe-plugin z ograniczonymi włączeniami / wykluczeniami. Bawiłem się CDI, kontaktując się z sonarem / jacoco, więc skończyłem w tym projekcie:

https://github.com/FibreFoX/cdi-sessionscoped-login/

Może ci to trochę pomoże. w moim pom.xml używam niejawnego „-javaagent”, ustawiając opcję argLine w sekcji konfiguracyjnej określonych wtyczek testowych. Jawne używanie ANT w projektach MAVEN jest czymś, czego nie spróbuję, dla mnie to za dużo mieszania dwóch światów.

Mam tylko jednomodułowy projekt Mavena, ale może pomoże ci dostosować twój do pracy.

uwaga: może nie wszystkie wtyczki maven są zaktualizowane, może niektóre problemy zostały naprawione w późniejszych wersjach

FibreFoX
źródło
Dzięki za to; Rzucę okiem i dam ci znać, jak to działa. To może nie być w tym tygodniu :)
Stewart
0

Ta próbka działa dla mnie bardzo dobrze:

<plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.2</version>
            <executions>
                <execution>
                    <id>pre-unit-test</id>
                    <goals>
                        <goal>prepare-agent</goal>
                    </goals>
                    <configuration>
                        <destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile>
                        <propertyName>surefireArgLine</propertyName>
                    </configuration>
                </execution>
                <execution>
                    <id>pre-integration-test</id>
                    <goals>
                        <goal>prepare-agent-integration</goal>
                    </goals>
                    <configuration>
                        <destFile>${project.build.directory}/coverage-reports/jacoco-it.exec</destFile>
                        <!--<excludes>
                            <exclude>com.asimio.demo.rest</exclude>
                            <exclude>com.asimio.demo.service</exclude>
                        </excludes>-->
                        <propertyName>testArgLine</propertyName>
                    </configuration>
                </execution>
                <execution>
                    <id>post-integration-test</id>
                    <phase>post-integration-test</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                    <configuration>
                        <dataFile>${project.build.directory}/coverage-reports/jacoco-it.exec</dataFile>
                        <outputDirectory>${project.reporting.outputDirectory}/jacoco-it</outputDirectory>
                    </configuration>
                </execution>
                <execution>
                    <id>post-unit-test</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                    <configuration>
                        <dataFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</dataFile>
                        <outputDirectory>${project.reporting.outputDirectory}/jacoco-ut</outputDirectory>
                    </configuration>
                </execution>
                <execution>
                    <id>merge-results</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>merge</goal>
                    </goals>
                    <configuration>
                        <fileSets>
                            <fileSet>
                                <directory>${project.build.directory}/coverage-reports</directory>
                                <includes>
                                    <include>*.exec</include>
                                </includes>
                            </fileSet>
                        </fileSets>
                        <destFile>${project.build.directory}/coverage-reports/aggregate.exec</destFile>
                    </configuration>
                </execution>
                <execution>
                    <id>post-merge-report</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                    <configuration>
                        <dataFile>${project.build.directory}/coverage-reports/aggregate.exec</dataFile>
                        <outputDirectory>${project.reporting.outputDirectory}/jacoco-aggregate</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.18.1</version>
            <configuration>
                <argLine>${surefireArgLine}</argLine>
                <!--<skipTests>${skip.unit.tests}</skipTests>-->
                <includes>
                    <include>**/*Test.java</include>
                    <!--<include>**/*MT.java</include>
                    <include>**/*Test.java</include>-->
                </includes>
            <!--    <skipTests>${skipUTMTs}</skipTests>-->
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.12.4</version>
            <configuration>
                <!--<skipTests>${skipTests}</skipTests>
                <skipITs>${skipITs}</skipITs>-->
                <argLine>${testArgLine}</argLine>
                <includes>
                    <include>**/*IT.java</include>
                </includes>
                <!--<excludes>
                    <exclude>**/*UT*.java</exclude>
                </excludes>-->
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
SerhatTopkaya
źródło
Proszę podać wyjaśnienie swojej odpowiedzi
mishsx
@mishsx Fajny artykuł wyjaśniający: natritmeyer.com/howto/…
SerhatTopkaya