J'ai cherché sur internet pour celui-ci. Il y a beaucoup de demi-réponses là-bas, à faire avec les propriétés Maven telles que ${sonar.jacoco.reportPath}
, ou org.jacoco:jacoco-maven-plugin:prepare-agent
ou réglage maven-surefire-plugin
argLine
avec -javaagent
.
Certains comment, aucune de ces réponses, seules ou combinées, ne produisent ce que je cherche: Un rapport de couverture qui montre une classe comme étant couverte si elle est utilisée dans des tests plus haut dans la pile, telles que les entités utilisées. DAO, même s’il n’était pas entièrement couvert par des tests dans son propre module.
Y at-il une configuration définitive quelque part, pour y parvenir, s'il vous plaît?
J'étais dans la même situation que vous, les demi-réponses dispersées sur Internet étaient assez énervantes, car il semblait que beaucoup de gens avaient le même problème, mais personne ne pouvait se soucier d'expliquer comment ils l'avaient résolu.
Les documents Sonar font référence à n projet GitHub avec des exemples qui sont utiles. Ce que j’ai fait pour résoudre ce problème a été d’appliquer la logique des tests d’intégration aux tests unitaires réguliers (bien que les tests unitaires appropriés doivent être spécifiques à un sous-module, ce n’est pas toujours le cas).
Dans le pom.xml parent, ajoutez ces propriétés:
<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>
Cela rendra les rapports de test des unités de ramassage Sonar pour tous les sous-modules au même endroit (un dossier cible dans le projet parent). Il demande également à Sonar de réutiliser les rapports exécutés manuellement au lieu de générer les siens. Nous avons juste besoin de faire fonctionner jacoco-maven-plugin pour tous les sous-modules en le plaçant dans le pom parent, à l'intérieur du build/plugins:
<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>
destFile
place le fichier de rapport à l'endroit où Sonar le recherchera et append
l'ajoutera au fichier au lieu de l'écraser. Cela combinera tous les rapports JaCoCo pour tous les sous-modules dans le même fichier.
Sonar examinera ce fichier pour chaque sous-module, car c’est ce que nous lui avons indiqué plus haut, ce qui nous donne les résultats des tests unitaires combinés pour les fichiers multi-modules dans Sonar.
Des questions qui me viennent à l'esprit depuis ce temps-là, je suis devenu fou de jacoco.
Oui. Vous devez utiliser agent jacoco qui fonctionne en mode output=tcpserver
, jacoco ant lib. Fondamentalement deux jar
s. Cela vous donnera 99% de succès.
Vous ajoutez une chaîne
-javaagent:[your_path]/jacocoagent.jar=destfile=/jacoco.exec,output=tcpserver,address=*
sur votre serveur d'applications Java_OPTS et redémarrez-le. Dans cette chaîne uniquement [your_path]
doivent être remplacés par le chemin vers jacocoagent.jar, stocké (stockez-le!) sur votre VM où le serveur d'applications s'exécute. Depuis ce temps, vous démarrez le serveur d'applications, toutes les applications déployées seront surveillés de manière dynamique et leur activité (ce qui signifie utilisation du code) sera prête pour que vous obteniez le format jacocos .exec sur demande tcl.
Oui, pour cela, vous avez besoin des scripts jacocoant.jar et ant build, situés dans votre espace de travail jenkins.
C'est vrai.
Jacoco maven plugin peut collecter des données de tests unitaires et certaines données de tests d’intégration (voir Arquillian Jacoco ), mais si vous avez par exemple des tests assurés en tant que version séparée dans jenkins, et que vous souhaitez afficher couverture multi-module, je ne vois pas comment le plugin maven peut vous aider.
Seules les données de couverture dans .exec
_ format. Le sonar peut alors le lire.
Non, le sonar le fait, mais pas le jacoco. Quand vous faites mvn sonar:sonar
chemin vers les classes entre en jeu.
Il doit être présenté dans votre espace de travail Jenkins. Mon script de fourmi, je l'ai appelé jacoco.xml
Ressemble à ça:
<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>
Deux paramètres obligatoires à passer lors de l’appel de ce script -Dworkspace=$WORKSPACE
utilisez-le pour indiquer votre espace de travail Jenkins et -Djacoco.Host=yourappserver.com
Hôte sans http://
Notez aussi que je mets mon jacocoant.jar
to $ {workspace} /tools/jacoco/jacocoant.jar
Avez-vous démarré votre serveur d'applications avec jacocoagent.jar?
Avez-vous mis ant script et jacocoant.jar dans votre espace de travail jenkins?
Si oui, la dernière étape consiste à configurer une génération Jenkins. Voici la stratégie:
jacocoReset
pour réinitialiser toutes les données précédemment collectées.jacocoReport
pour obtenir un rapportSi tout va bien, vous verrez it-jacoco.exec
dans votre espace de travail de construction.
Regardez la capture d’écran. ant
est également installé dans mon espace de travail dans $WORKSPACE/tools/ant
_ dir, mais vous pouvez en utiliser un qui est installé dans vos jenkins.
Maven sonar:sonar
fera le travail (n'oubliez pas de le configurer), pointez-le sur pom.xml principal pour qu'il passe par tous les modules. Utilisation sonar.jacoco.itReportPath=$WORKSPACE/it-jacoco.exec
paramètre indiquant au sonar où se trouve votre rapport de test d'intégration. Chaque fois qu'il analysera de nouvelles classes de modules, il recherchera des informations sur la couverture dans it-jacoco.exec
.
Par défaut mvn sonar:sonar
fait clean
et supprime votre répertoire cible, utilisez sonar.dynamicAnalysis=reuseReports
pour l'éviter.
Depuis la version 0.7.7, il existe un nouveau moyen de créer un rapport agrégé:
Vous créez un projet 'rapport' distinct qui collecte tous les rapports nécessaires (Tout objectif du projet d'agrégateur est exécuté avant ses modules et ne peut donc pas être utilisé. utilisé).
aggregator pom
|- parent pom
|- module a
|- module b
|- report module
Le pom racine ressemble à ceci (n'oubliez pas d'ajouter le nouveau module de rapport sous modules):
<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>
Les poms de chaque sous-module n'ont pas besoin d'être changés du tout. Le pom du module de rapport ressemble à ceci:
<!-- 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>
Un exemple complet peut être trouvé ici .
Je vais poster ma solution car elle est légèrement différente des autres et me prend également une journée solide pour bien faire les choses, avec l’aide des réponses existantes.
Pour un projet Maven multi-module:
ROOT
|--WAR
|--LIB-1
|--LIB-2
|--TEST
Lorsque le projet WAR
est la principale application Web, LIB
1 et 2 sont des modules supplémentaires dont dépend WAR
et TEST
est l'emplacement des tests d'intégration. TEST
crée une instance Tomcat intégrée (pas via le plugin Tomcat), exécute le projet WAR
et les teste via un ensemble de tests JUnit. Les projets WAR
et LIB
possèdent tous les deux leurs propres tests unitaires.
Le résultat de tout cela est que la couverture d’intégration et de tests unitaires est séparée et peut être distinguée dans 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
et TEST
pom.xml
héritera de l'exécution des plugins 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>
J'ai également constaté que article de blog Petri Kainulainens 'Création de rapports de couverture de code pour les tests unitaires et d'intégration avec le plug-in JaCoCo Maven' est précieux pour la configuration de JaCoCo.
La configuration que j'utilise dans mon pom de niveau parent où j'ai des phases de test unitaires et d'intégration distinctes.
Je configure les propriétés suivantes dans les propriétés POM parent
<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>
Je place les définitions de plugin sous la gestion du plugin.
Notez que je définis une propriété pour les arguments surefire (surefireArgLine) et failafe (failofafeArgLine) afin de permettre à jacoco de configurer le javaagent afin qu'il s'exécute avec chaque test.
Sous 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>
...
Et dans la section de construction
<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>
....
Et dans la section des rapports
<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>
Il y a un moyen d'accomplir cela. La magie consiste à créer un fichier combiné jacoco.exec. Et avec maven 3.3.1, il existe un moyen simple de l'obtenir. Voici mon 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>
Si vous ajoutez ce profil à votre pom parent et appelez mvn clean install sonar:sonar -DrunSonar
, Vous obtenez la couverture complète.
La magie ici est maven.multiModuleProjectDirectory
. Ce dossier est toujours le dossier où vous avez commencé votre construction Maven.
<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>
Vous pouvez appeler une tâche ant appelée fusionner sur maven, pour mettre tous les fichiers de couverture (* .exec) ensemble dans le même fichier. fichier.
Si vous exécutez des tests unitaires, utilisez la phase prepare-package , si vous exécutez un test d'intégration, utilisez donc après l'intégration. -test .
Ce site a un exemple de la façon dont appelez jacoco ant task dans le projet maven
Vous pouvez utiliser ce fichier fusionné sur le sonar.
pour effectuer des tests unitaires ET des tests d'intégration, vous pouvez utiliser maven-surefire-plugin et maven-failafe-plugin avec des inclus/exclus limités. Je jouais avec CDI tout en prenant contact avec sonar/jacoco, je me suis donc retrouvé dans ce projet:
https://github.com/FibreFoX/cdi-sessionscoped-login/
Peut-être que cela vous aide un peu. Dans mon fichier pom.xml, j'utilise implicitement "-javaagent" en définissant l'option argLine dans la section configuration des plug-ins de test spécifiés. L'utilisation explicite d'ANT dans les projets MAVEN est quelque chose que je n'essaierais pas, pour moi c'est trop mélanger deux mondes.
Je n'ai qu'un projet Maven à un seul module, mais il vous aidera peut-être à adapter le vôtre au travail.
note: peut-être que tous les plugins maven ne sont pas up2date, peut-être que certains problèmes sont résolus dans les versions ultérieures