Wie konfiguriere ich Maven + Sonar + JaCoCo mit mehreren Modulen, um einen Bericht über die zusammengeführte Abdeckung zu erstellen?

127

Ich habe im Internet nach diesem gesucht. Es gibt viele halbe Antworten, die mit Maven-Eigenschaften wie ${sonar.jacoco.reportPath}oder org.jacoco:jacoco-maven-plugin:prepare-agentoder Einstellung maven-surefire-plugin argLinemit zu tun haben -javaagent.

In gewisser Weise führt keine dieser Antworten allein oder in Kombination zu dem, wonach ich suche: Ein Abdeckungsbericht, der eine Klasse als abgedeckt anzeigt, wenn sie in Tests weiter oben im Stapel verwendet wird, z. B. verwendete Entitäten von DAOs, obwohl es nicht vollständig durch Tests in einem eigenen Modul abgedeckt wurde.

Gibt es irgendwo eine definitive Konfiguration, um dies zu erreichen, bitte?

Stewart
quelle

Antworten:

163

Ich war in der gleichen Situation wie Sie. Die im Internet verstreuten halben Antworten waren ziemlich ärgerlich, da es den Anschein hatte, dass viele Menschen das gleiche Problem hatten, aber niemand konnte sich die Mühe machen, vollständig zu erklären, wie sie es gelöst haben.

Die Sonar-Dokumente beziehen sich auf ein GitHub-Projekt mit hilfreichen Beispielen . Um dies zu lösen, habe ich die Logik der Integrationstests auf reguläre Komponententests angewendet (obwohl ordnungsgemäße Komponententests submodulspezifisch sein sollten, ist dies nicht immer der Fall).

Fügen Sie in der übergeordneten Datei pom.xml die folgenden Eigenschaften hinzu:

<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>

Dadurch kann Sonar Unit-Testberichte für alle Submodule an derselben Stelle abrufen (ein Zielordner im übergeordneten Projekt). Außerdem wird Sonar angewiesen, manuell ausgeführte Berichte wiederzuverwenden, anstatt eigene Berichte zu erstellen. Wir müssen nur das Jacoco-Maven-Plugin für alle Submodule laufen lassen, indem wir dies im übergeordneten POM in Build / Plugins platzieren:

<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>

destFilePlatziert die Berichtsdatei an der Stelle, an der Sonar danach sucht, und appendlässt sie an die Datei anhängen, anstatt sie zu überschreiben. Dadurch werden alle JaCoCo-Berichte für alle Submodule in derselben Datei kombiniert.

Sonar wird diese Datei für jedes Submodul untersuchen, da wir ihn oben darauf hingewiesen haben, was uns kombinierte Unit-Testergebnisse für Multi-Modul-Dateien in Sonar liefert.

mpontes
quelle
Wunderbar! Das hat funktioniert. Schließlich! Ich denke, die magische fehlende lebenswichtige Beschwörung, die mir fehlte, war <append> true </ append>
Stewart
Es klappt! Ich musste mvn packagevor dem Ausführen mvn sonar:sonareine neue erstellen, um den neuen Berichtspfad zu generieren.
Thomasa88
2
Gemäß dem Beispiel sollte die Eigenschaft "sonar.jacoco.itReportPath" verwendet werden, um zusammengeführte Ergebnisse in "Gesamtcodeabdeckung" zu erhalten. Bitte aktualisieren Sie die Antwort.
Yves Martin
4
"sonar.dynamicAnalysis" ist ebenfalls veraltet: docs.sonarqube.org/display/SONAR/Release+4.3+Upgrade+Notes
Yves Martin
3
Aktualisierter Link: docs.sonarqube.org/display/SONARQUBE53/…
Lonzak
23

FAQ

Fragen aus dem Kopf seitdem bin ich verrückt nach Jacoco geworden.

Mein Anwendungsserver (jBoss, Glassfish ..) befindet sich im Irak, Syrien, was auch immer. Ist es möglich, eine Abdeckung mit mehreren Modulen zu erhalten, wenn Integrationstests darauf ausgeführt werden? Jenkins und Sonar befinden sich ebenfalls auf verschiedenen Servern.

Ja. Sie müssen jacoco agent verwenden , der im Modus output=tcpserverjacoco ant lib ausgeführt wird. Grundsätzlich zwei jars. Dies gibt Ihnen 99% Erfolg.

Wie funktioniert Jacoco Agent?

Sie fügen eine Zeichenfolge hinzu

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

auf Ihren Anwendungsserver JAVA_OPTS und starten Sie ihn neu. In dieser Zeichenfolge muss nur [your_path]der Pfad zu jacocoagent.jar ersetzt werden, der auf Ihrer VM gespeichert (gespeichert!) Ist, auf der der App-Server ausgeführt wird. Seit dem Start des App-Servers werden alle bereitgestellten Anwendungen dynamisch überwacht und ihre Aktivität (dh die Verwendung von Code) kann von Ihnen per tcl-Anforderung im jacocos .exec-Format abgerufen werden.

Könnte ich den jacoco-Agenten zurücksetzen, um erst seit Beginn meines Tests mit der Erfassung von Ausführungsdaten zu beginnen?

Ja, zu diesem Zweck benötigen Sie das Build-Skript jacocoant.jar und ant in Ihrem Jenkins-Arbeitsbereich.

Was ich also von http://www.eclemma.org/jacoco/ benötige, ist jacocoant.jar in meinem Jenkins-Arbeitsbereich und jacocoagent.jar auf meiner App-Server-VM?

Das stimmt.

Ich möchte keine Ameise verwenden, ich habe gehört, dass das Jacoco Maven Plugin all diese Dinge auch kann.

Das ist nicht richtig, das jacoco maven Plugin kann Unit-Testdaten und einige Integrationstestdaten sammeln (siehe Arquillian Jacoco ), aber wenn Sie zum Beispiel Tests als separate Build-in-Jenkins versichern und die Abdeckung mehrerer Module zeigen möchten, kann ich das Ich sehe nicht, wie das Maven-Plugin Ihnen helfen kann.

Was genau produziert Jacoco Agent?

Nur Abdeckungsdaten im .execFormat. Sonar kann es dann lesen.

Muss Jacoco wissen, wo sich meine Java-Klassen befinden?

Nein, Sonar, aber kein Jacoco. Wenn Sie den mvn sonar:sonarWeg zum Unterricht gehen, kommt er ins Spiel.

Was ist also mit dem Ameisenskript?

Es muss in Ihrem Jenkins-Arbeitsbereich präsentiert werden. Mein Ameisenskript, ich habe es jacoco.xmlso genannt:

<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>

Zwei obligatorische Parameter, die Sie beim Aufrufen dieses Skripts übergeben sollten, -Dworkspace=$WORKSPACE verwenden es, um auf Ihren Jenkins-Arbeitsbereich zu verweisen und -Djacoco.host=yourappserver.comohne zu hostenhttp://

jacocoant.jarBeachten Sie auch, dass ich meine in $ {workspace} /tools/jacoco/jacocoant.jar platziere

Was soll ich als nächstes tun?

Haben Sie Ihren App-Server mit jacocoagent.jar gestartet?

Haben Sie Ant Script und jacocoant.jar in Ihren Jenkins-Arbeitsbereich eingefügt?

Wenn ja, besteht der letzte Schritt darin, einen Jenkins-Build zu konfigurieren. Hier ist die Strategie:

  1. Rufen Sie ant target jacocoResetauf, um alle zuvor gesammelten Daten zurückzusetzen.
  2. Führen Sie Ihre Tests aus
  3. Rufen Sie das Ameisenziel auf jacocoReport, um einen Bericht zu erhalten

Wenn alles in Ordnung ist, sehen Sie it-jacoco.execin Ihrem Build-Arbeitsbereich.

Schauen Sie sich den Screenshot an, den ich auch antin meinem Arbeitsbereich in $WORKSPACE/tools/antdir installiert habe , aber Sie können einen verwenden, der in Ihren Jenkins installiert ist.

Geben Sie hier die Bildbeschreibung ein

Wie kann man diesen Bericht im Sonar pushen?

Maven sonar:sonarerledigt den Job (vergessen Sie nicht, ihn zu konfigurieren) und zeigt auf die Hauptdatei pom.xml, damit er alle Module durchläuft. Verwenden Sie den sonar.jacoco.itReportPath=$WORKSPACE/it-jacoco.execParameter, um dem Sonar mitzuteilen, wo sich Ihr Integrationstestbericht befindet. Jedes Mal, wenn neue Modulklassen analysiert werden, wird nach Informationen zur Abdeckung in gesucht it-jacoco.exec.

Ich habe bereits jacoco.exec in meinem `target`-Verzeichnis,` mvn sonar: sonar` ignoriert / entfernt es

Standardmäßig mvn sonar:sonarwird cleanIhr Zielverzeichnis gelöscht, um dies sonar.dynamicAnalysis=reuseReportszu vermeiden.

ZuzEL
quelle
20

NEUER WEG SEIT VERSION 0.7.7

Seit Version 0.7.7 gibt es eine neue Möglichkeit, einen aggregierten Bericht zu erstellen:

Sie erstellen ein separates 'Bericht'-Projekt, das alle erforderlichen Berichte sammelt (Jedes Ziel im Aggregator-Projekt wird vor seinen Modulen ausgeführt, daher kann es nicht verwendet werden).

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

Das Root-Pom sieht folgendermaßen aus (vergessen Sie nicht, das neue Berichtsmodul unter Module hinzuzufügen):

<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>

Die Poms von jedem Submodul müssen überhaupt nicht geändert werden. Der Pom aus dem Berichtsmodul sieht folgendermaßen aus:

<!-- 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>

Ein vollständiges Beispiel finden Sie hier .

Lonzak
quelle
3
Das funktioniert. Der aggregierte Bericht zeigt die kumulative Codeabdeckung für alle Module. Haben Sie jemals versucht, diesen kumulativen Bericht in Sonar anzuzeigen? Ich habe sonar-qube verwendet, um jacoco.exec für einzelne Berichte zu lesen, aber mit diesem Berichtsaggregat wird im Berichtsmodul keine aggregierte jacoco.exec angezeigt.
Swetha V
@ SwethaV Erfolgreich dabei? Wir sind in der gleichen Position und müssen einen Weg finden, um die aggregierte Exec zu generieren :)
Vinky
Wir verwenden Sonar Qube Version 6.X, das eine eigene Testabdeckungsseite hat, daher brauche ich dort keinen Jacoco. Für eine ältere Version haben wir das Cobertura-Plugin installiert, das auch diese Funktionalität bietet ...
Lonzak
11

Ich werde meine Lösung veröffentlichen, da sie sich geringfügig von anderen unterscheidet, und ich habe auch einen guten Tag gebraucht, um sie mithilfe der vorhandenen Antworten richtig zu machen.

Für ein Maven-Projekt mit mehreren Modulen:

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

Wenn das WARProjekt die Hauptwebanwendung ist, sind LIB1 und 2 zusätzliche Module, WARvon TESTdenen die Integrationstests abhängen . TESTStartet eine eingebettete Tomcat-Instanz (nicht über das Tomcat-Plugin), führt das WARProjekt aus und testet sie über eine Reihe von JUnit-Tests. Die WARund LIBProjekte haben beide ihre eigenen Unit-Tests.

Das Ergebnis all dessen ist, dass die Integration und die Abdeckung von Komponententests getrennt sind und in SonarQube unterschieden werden können.

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 Und TEST pom.xmldie die JaCoCo Plugins Ausführung erben.

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>

Ich fand auch Petri Kainulainens Blog-Post 'Erstellen von Code-Coverage-Berichten für Unit- und Integrationstests mit dem JaCoCo Maven Plugin' für die JaCoCo-Setup-Seite von Nutzen.

Markdsievers
quelle
Ich muss diesen Beitrag irgendwann aktualisieren, da er eigentlich etwas suboptimal ist. agent-for-itDies ist nur erforderlich, wenn die Tests im TESTModul ausgeführt werden. In der aktuellen Konfiguration wird es jedoch für jedes andere Modul ausgeführt, für das es keinen Wert hat. Die Verbesserung wäre, agent-for-utin allen anderen Modulen agent-for-itgelaufen zu sein und nur in zu laufen TEST.
Markdsievers
6

Die Konfiguration, die ich in meinem übergeordneten POM verwende, wo ich separate Einheiten- und Integrationstestphasen habe.

Ich konfiguriere die folgenden Eigenschaften in den übergeordneten POM-Eigenschaften

    <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>

Ich platziere die Plugin-Definitionen unter Plugin-Verwaltung.

Beachten Sie, dass ich eine Eigenschaft für die Argumente safefire (surefireArgLine) und failafe (failafeArgLine) definiere, damit jacoco den Java-Agenten so konfigurieren kann, dass er bei jedem Test ausgeführt wird.

Unter pluginManagement

  <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>
            ...

Und im Build-Bereich

 <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>
        ....

Und im Berichtsbereich

    <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
quelle
1
Ich sehe, Sie haben die <append>true</append>Konfiguration unter den prepare-agentAbschnitten ...
Stewart
Betonung. Lesen Sie meinen Kommentar zu einer anderen Antwort. Es war die fehlende wichtige Zutat für mich, die ich in anderen Dokumenten nicht gefunden habe.
Stewart
Hast du einen Github-Link dafür? Ich möchte genau ähnliche Konfigurationen machen
Rohit Kasat
@Rhit - nein, ich nicht, zumindest nicht in einem öffentlichen Repository.
Sweetfa
Dies funktioniert sehr gut mit Sonar Qube Version 6.5 (Build 27846) ...: D Die Codeabdeckung wird korrekt angezeigt.
Udoline
6

Es gibt einen Weg, dies zu erreichen. Die Magie besteht darin, eine kombinierte jacoco.exec-Datei zu erstellen. Und mit Maven 3.3.1 gibt es eine einfache Möglichkeit, dies zu erreichen. Hier mein 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>

Wenn Sie dieses Profil zu Ihrem Eltern-Pom hinzufügen und anrufen, erhalten mvn clean install sonar:sonar -DrunSonarSie die vollständige Abdeckung.

Die Magie hier ist maven.multiModuleProjectDirectory. Dieser Ordner ist immer der Ordner, in dem Sie Ihren Maven-Build gestartet haben.

Sven Oppermann
quelle
Dies funktionierte für mich, nachdem ich zahlreiche andere Lösungen durchlaufen hatte.
Jimson Kannanthara James
Das einzige Problem war, dass ich mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.4.0.905:sonar -DrunSonaraufgrund eines A required class was missing while executing org.sonarsource.scanner.maven:sonar-maven-plugin:3.0.1:sonar: org/sonar/batch/bootstrapper/IssueListenerFehlers ein Sonar mit Befehl ausführen musste .
Jimson Kannanthara James
1
Benutze diese Magie nicht. Die angegebene Eigenschaft ist ein Implementierungsdetail und darf nicht als verlässlich angesehen werden. - Das Maven-Entwicklerteam
Michael-O
4

Ich habe eine andere Lösung für neue Sonar-Versionen gefunden, bei der das binäre Berichtsformat von JaCoCo (* .exec) veraltet ist und das bevorzugte Format XML (SonarJava 5.12 und höher) ist. Die Lösung ist sehr einfach und ähnelt der vorherigen Lösung mit * .exec-Berichten im übergeordneten Verzeichnis aus diesem Thema: https://stackoverflow.com/a/15535970/4448263 .

Angenommen, unsere Projektstruktur ist:

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

Sie benötigen die folgende Konfiguration des Maven Build Plugins im POM des Aggregatprojekts:

<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>

Dann baue ein Projekt mit maven:

mvn clean verify

Und für Sonar sollten Sie die Eigenschaft in der Verwaltungs-GUI festlegen:

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

oder über die Kommandozeile:

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

Beschreibung

Dadurch werden Binärberichte für jedes Modul in Standardverzeichnissen erstellt : target/jacoco.exec. Anschließend werden XML-Berichte für jedes Modul in Standardverzeichnissen erstellt : target/site/jacoco/jacoco.xml. Anschließend wird für jedes Modul im benutzerdefinierten Verzeichnis ein aggregierter Bericht erstellt, der für jedes Modul ${project.basedir}/../target/site/jacoco-aggregate/relativ zum übergeordneten Verzeichnis ist. Für Modul A und Modul B ist dies ein gemeinsamer Pfad moduleC/target/site/jacoco-aggregate/.

Da Modul B von Modul A abhängt, wird Modul B zuletzt erstellt und sein Bericht wird als aggregierter Abdeckungsbericht in Sonar für beide Module A und B verwendet.

Zusätzlich zum Aggregatbericht benötigen wir einen normalen Modulbericht, da JaCoCo-Aggregatberichte nur Abdeckungsdaten für Abhängigkeiten enthalten.

Zusammen bieten diese beiden Arten von Berichten vollständige Abdeckungsdaten für Sonar.

Es gibt eine kleine Einschränkung: Sie sollten in der Lage sein, einen Bericht in das übergeordnete Verzeichnis des Projekts zu schreiben (sollte über die Berechtigung verfügen). Oder Sie können die Eigenschaft jacoco.skip=truein der pom.xml (moduleC) des Root-Projekts und jacoco.skip=falsein Modulen mit Klassen und Tests (moduleA und moduleB) festlegen.

Keddok
quelle
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>             
Mike
quelle
2

Als Sonare sonar.jacoco.reportPath, sonar.jacoco.itReportPathund sonar.jacoco.reportPathsalle sind veraltet , sollten Sie sonar.coverage.jacoco.xmlReportPathsjetzt verwenden. Dies hat auch Auswirkungen, wenn Sie ein Maven-Projekt mit mehreren Modulen mit Sonar und Jacoco konfigurieren möchten.

Wie @Lonzak wies darauf hin , da Sonar 0.7.7 können Sie Sonars Bericht aggragation Ziel verwenden. Geben Sie einfach die folgende Abhängigkeit in Ihr übergeordnetes Element ein:

<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>

Da aktuelle Versionen des jacoco-maven-Plugins mit den XML-Berichten kompatibel sind, wird für jedes Modul in seinem eigenen Zielordner ein Site- / Jacoco-Aggregat-Ordner erstellt, der eine jacoco.xmlDatei enthält.

Verwenden Sie den folgenden Befehl, damit Sonar alle Module kombiniert:

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

Um meine Antwort kurz und präzise zu halten, habe ich die maven-surefire-pluginund maven-failsafe-pluginAbhängigkeiten nicht erwähnt . Sie können sie einfach ohne andere Konfiguration hinzufügen:

<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
quelle
1

Sie können eine Ant-Task namens Merge on Maven aufrufen, um alle Coverage-Dateien (* .exec) in derselben Datei zusammenzufassen.

Wenn Sie Unit-Tests ausführen, verwenden Sie das Phase- Prepare-Paket . Wenn Sie einen Integrationstest ausführen, verwenden Sie den Post-Integration-Test .

Diese Seite enthält ein Beispiel dafür, wie man Jacoco Ant Task im Maven-Projekt aufruft

Sie können diese zusammengeführte Datei auf dem Sonar verwenden.

Andre Piantino
quelle
0

Für Unit-Tests UND Integrationstests können Sie das Maven-Surefire-Plugin und das Maven-Fail-Safe-Plugin mit eingeschränkten Ein- / Ausschlüssen verwenden. Ich habe mit CDI gespielt, als ich mit Sonar / Jacoco in Kontakt getreten bin, also bin ich in diesem Projekt gelandet:

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

Vielleicht hilft es dir ein bisschen. In meiner pom.xml verwende ich implizit "-javaagent", indem ich die argLine-Option im Konfigurationsabschnitt der angegebenen Test-Plugins setze. Die explizite Verwendung von ANT in MAVEN-Projekten würde ich nicht versuchen, für mich ist es zu viel, zwei Welten zu mischen.

Ich habe nur ein Maven-Projekt mit einem Modul, aber vielleicht hilft es Ihnen, Ihr Projekt an die Arbeit anzupassen.

Hinweis: Möglicherweise sind nicht alle Maven-Plugins auf dem neuesten Stand, möglicherweise wurden einige Probleme in späteren Versionen behoben

FibreFoX
quelle
Danke dafür; Ich werde einen Blick darauf werfen und Sie wissen lassen, wie es funktioniert. Könnte aber diese Woche nicht sein :)
Stewart
0

Dieses Beispiel funktioniert sehr gut für mich:

<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
quelle
Bitte geben Sie eine Erklärung für Ihre Antwort
mishsx
@mishsx Ein schöner Artikel zur Erklärung: natritmeyer.com/howto/…
SerhatTopkaya