J'utilise maven avec le plugin jacoco pour générer des métriques de couverture de code. J'ai quelques difficultés à configurer le plug-in surefire avec les options Java requises par le plug-in jacoco. J'ai déjà trouvé des réponses à propos de ceci déjà sur Stack Overflow mais quelque chose ne fonctionne pas pour moi.
J'ai un projet multi-module, et l'un de mes modules configure le plugin surefire comme suit:
foo/pom.xml
:
<plugins>
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-XX:MaxPermSize=512m</argLine>
</configuration>
</plugin>
</plugins>
Cela fonctionne comme prévu.
Maintenant, je veux incorporer jacoco pour obtenir des métriques de couverture de code, alors j'ai ajouté un profil CodeCoverage qui gère toute la configuration de jacoco:
parent/pom.xml
:
<profile>
<id>CodeCoverage</id>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals><goal>prepare-agent</goal></goals>
<configuration>
<propertyName>surefire.argLine</propertyName>
</configuration>
...
</execution>
<executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
On voit ici que si le profil CodeCoverage est spécifié, le plug-in jacoco est configuré pour utiliser la propriété surefire.argLine
, et cette propriété est utilisée pour configurez le argLine
pour le plugin surefire.
J'ai ensuite mis à jour le fichier pom.xml du module foo afin d'utiliser la propriété surefire.argLine
générée par le plugin jacoco:
foo/pom.xml
:
<plugins>
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>${surefire.argLine} -XX:MaxPermSize=512m</argLine>
</configuration>
</plugin>
</plugins>
Cette approche est spécifiée dans la documentation du plugin jacoco (voir [1]).
Quand je construis le module truc avec le profil CodeCoverage, je vois ce qui suit:
[foo] $ mvn clean install -X -PCodeCoverage
...
[INFO] --- jacoco-maven-plugin:0.7.0.201403182114:prepare-agent (jacoco-initialize) @ foo ---
[INFO] surefire.argLine set to -javaagent:...\\org.jacoco.agent\\0.7.0.201403182114\\org.jacoco.agent-0.7.0.201403182114-runtime.jar=destfile=...\foo\\\target\\coverage-reports\\jacoco-ut.exec
...
[DEBUG] Configuring mojo 'org.Apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator -->
[DEBUG] (s) argLine = -javaagent:...\\org.jacoco.agent\\0.7.0.201403182114\\org.jacoco.agent-0.7.0.201403182114-runtime.jar=destfile=...\\foo\\target\\coverage-reports\\jacoco-ut.exec -XX:MaxPermSize=512m
...
[INFO] --- jacoco-maven-plugin:0.7.0.201403182114:report (jacoco-site) @ foo ---
[INFO] Analyzed bundle 'Foo' with 59 classes`
Ainsi, le plugin jacoco est exécuté, une propriété surefire.argLine
est créée, le argLine
du plugin surefire utilise le code surefire.argLine
la propriété et l'argument local MaxPermSize
, et un fichier target\code-coverage\jacoc-ut-exec
est généré, comme prévu.
Cependant, si je n'utilise pas le profil CodeCoverage, je reçois une erreur car la propriété ${surefire.argLine}
(utilisée dans foo/pom.xml
) n'est pas créée par le jacoco plugin, et n'est défini nulle part:
[foo] $ mvn clean install -X
...
[DEBUG] Configuring mojo 'org.Apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator -->
[DEBUG] (s) argLine = ${surefire.argLine} -XX:MaxPermSize=512m
...
Error: Could not find or load main class ${surefire.argLine}`
Sinec le plugin jacoco n'a pas été appelé, aucune propriété surefire.argLine
n'a été créée, d'où l'erreur.
Donc, je retourne au parent/pom.xml
et crée cette propriété, sans valeur initiale:
parent/pom.xml
:
<properties>
<surefire.argLine></surefire.argLine>
</properties>
Maintenant, lorsque je construis le module truc sans utiliser le profil CodeCoverage, je ne reçois aucune erreur:
[foo] $ mvn clean install -X
...
[DEBUG] Configuring mojo 'org.Apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator -->
[DEBUG] (s) argLine = -XX:MaxPermSize=512m
...
[INFO] BUILD SUCCESS`
Le surefire argline est maintenant correct (en utilisant la propriété vide surefire.argLine
) et il n'y a pas de répertoire target\code-coverage
, comme prévu.
Alors maintenant, je retourne à la génération de métriques de code, en utilisant le profil CodeCoverage:
[foo] $ mvn clean install -X -PCodeCoverage
...
[INFO] --- jacoco-maven-plugin:0.7.0.201403182114:prepare-agent (jacoco-initialize) @ foo ---
[INFO] surefire.argLine set to -javaagent:...\\org.jacoco.agent\\0.7.0.201403182114\\org.jacoco.agent-0.7.0.201403182114-runtime.jar=destfile=...\\foo\\target\\coverage-reports\\jacoco-ut.exec
...
[DEBUG] Configuring mojo 'org.Apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator -->
[DEBUG] (s) argLine = -XX:MaxPermSize=512m
...
[INFO] --- jacoco-maven-plugin:0.7.0.201403182114:report (jacoco-site) @ foo ---
[INFO] Skipping JaCoCo execution due to missing execution data file:...\foo\target\coverage-reports\jacoco-ut.exec
On peut observer ici que le plugin jacoco est invoqué et définit la propriété surefire.argLine
, mais la propriété surefire.argLine
avec la valeur vide définie dans le parent/pom.xml
est utilisé pour créer l'argline du plugin surefire.
En conséquence, il n'y a pas de fichier jacoco-ut.exec
ni de répertoire target\code-coverage
lorsque j'utilise le profil CodeCoverage.
Je ne suis pas sûr de ce que je fais mal ici. Je déclare une propriété argLine
comme suggéré par la documentation jacoco, et je l'utilise chaque fois qu'un plugin surefire doit spécifier un argument supplémentaire. D'autres réponses sur Stack Overflow suggèrent de créer une propriété portant le même nom que la propriété jacoco argLine pour gérer le cas où jacoco n'est pas appelé.
Aucune suggestion?
modifier
Peut-être qu'une solution consiste à déclarer explicitement la propriété surefire.argLine
dans le profil CodeCoverage et à oublier d'utiliser le argLine
du plugin jacoco :
<profile>
<id>CodeCoverage</id>
<properties>
<surefire.argLine>-javaagent:${jacoco.agent.jar}=destfile=${jacoco.report.path}</surefire.argLine>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<!-- no longer specifying 'argLine' for jacoco plugin ... -->
</execution>
<executions>
</plugin>
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- ... instead the arg line is configured explicitly for surefire plugin. -->
<argLine>${surefire.argLine}</argLine>
</configuration>
</plugin>
</plugins>
</plugin>
</build>
Cela créera la propriété surefire.argLine qui utilisera l'agent Java requis par le plugin jacoco, et configurera le surefire plug-in pour utiliser cette propriété dans ses arguments JVM. Le plug-in jacoco créera désormais une propriété argLine, mais sera ignoré. Ce n'est pas une solution élégante Je fais des hypothèses sur le fonctionnement du plugin jacoco, et cela pourrait changer dans une version ultérieure).
modifier
La propriété jacoco.agent.jar
doit également être définie, en pointant sur son emplacement dans le référentiel local (vous ne savez pas si cela est robuste) ou en utilisant le plugin dependency pour copier le fichier jacoco Agent jar dans le répertoire de construction local:
<profile>
<id>CodeCoverage</id>
<properties>
<jacoco.agent.jar>${project.build.directory}/jacoco-agent.jar</jacoco.agent.jar>
...
</project>
<build>
...
<plugins>
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>download-jacoco-agent</id>
<phase>process-test-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<version>${jacoco.version}</version>
<classifier>runtime</classifier>
<outputDirectory>${project.build.directory}</outputDirectory>
<destFileName>jacoco-agent.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
modifier
Pas sûr si utiliser le plugin dependency est la bonne approche, ou pointer vers l'artefact de l'agent jacoco dans le référentiel local:
<profile>
<id>CodeCoverage</id>
<properties>
<jacoco.agent.jar>${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco.version}/org.jacoco.agent-${jacoco.version}-runtime.jar</jacoco.agent.jar>
</properties>
...
</profile>
Ceci est plus simple et ne nécessite pas la copie d'un artefact dans le répertoire de construction local, mais est fragile: des modifications dans la structure du référentiel annuleront cela.
[1] http://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html
Depuis le jacoco-maven-plugin:prepare-agent
L’objectif s’exécutant avant le plugin maven-surefire, essayez d’ajouter le ${argLine}
variable dans la valeur argLine
définie par le plugin maven-surefire.
Exemple:
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.1</version>
<configuration>
<argLine>-server -ea -XX:MaxPermSize=256m -Xmx4g -XX:-UseSplitVerifier ${argLine}</argLine>
</configuration>
</plugin>
J'ai eu le même problème et cette solution a fonctionné pour moi, sans qu'il soit nécessaire de reconfigurer d'autres sections du POM.
Essayez d'utiliser
@{argLine}
au lieu de
${argLine}
(ou surefire.argLine
dans ton cas)
Cela permet à surefire de lire une propriété modifiée par d’autres plugins au lieu de lire celle substituée par Maven elle-même. Ensuite, vous pouvez définir le paramètre argLine
pour le vider dans les propriétés Maven:
<properties>
<argLine></argLine>
</properties>
Ce qui maintenant ne causera aucun problème. Plus ici: Comment utiliser les propriétés définies par d’autres plugins dans argLine?
Si votre projet utilise déjà l'argLine pour configurer le surefire-maven-plugin, assurez-vous que l'argLine est défini comme une propriété plutôt que dans le cadre de la configuration du plugin. Par exemple:
<properties>
<argLine>-your -extra -arguments</argLine>
</properties>
...
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- Do not define argLine here! -->
</configuration>
</plugin>
Les informations de couverture résultantes sont collectées pendant l'exécution et écrites par défaut dans un fichier à la fin du processus.
Travaillé pour moi Voir: http://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html
Essayez d'ajouter la propriété argLine dans la section des propriétés (comme indiqué dans le code ci-dessous) au lieu de l'ajouter dans la section de configuration du plug-in maven-sure-fire. Le plugin Jacoco maven va juste s’ajouter à cela et tout fonctionnera comme prévu.
<properties>
<argLine>-XX:MaxPermSize=512m</argLine>
</properties>
Voir https://docs.sonarqube.org/display/PLUG/Usage+of+JaCoCo+with+Java+Plugin
Ma solution consiste à utiliser plusieurs profils.
Le premier profil définit une valeur vide pour le surefire.argLine
et le failsafe.argLine
et est actif par défaut.
<profile>
<id>not-sonar</id>
<properties>
<surefire.argLine/>
<failsafe.argLine/>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
Le second profil a la configuration du plugin jacoco et est inactif par défaut.
<profile>
<id>sonar</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin-version}</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<propertyName>surefire.argLine</propertyName>
</configuration>
</execution>
<execution>
<id>default-prepare-agent-integration</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<propertyName>failsafe.argLine</propertyName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Lorsque vous activez le profil sonar, le profil non-sonar est automatiquement désactivé.
Cela devrait être un peu plus élégant que d'utiliser d'autres plugins pour faire le travail à votre place. Vous pouvez maintenant utiliser le ${surefire.argLine}
variable dans votre argument et il existera toujours et sera défini lorsque vous exécuterez votre construction.
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>${surefire.argLine} -XX:MaxPermSize=512m</argLine>
</configuration>
</plugin>
Si vous rencontrez toujours des problèmes parce que $ {surefire.argLine} n'a pas de valeur, vous pouvez également définir une propriété factice comme ceci:
<profile>
<id>not-sonar</id>
<properties>
<surefire.argLine>-DdummyProperty=notUsed</surefire.argLine>
<failsafe.argLine>-DdummyProperty=notUsed</failsafe.argLine>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
J'ai récemment rencontré le même problème et ai même implicitement pris les mêmes mesures que celles que vous avez décrites avec le même résultat. Aucune solution propre que j'ai trouvée n'a fonctionné pour moi.
J'ai donc exécuté plusieurs étapes en mode débogage et il semble que Maven remplace deux fois les propriétés. Ce n’est pas seulement paresseux, comme je le pensais, mais de manière avide et paresseuse:
properties
de POM et probablement aussi settings.xml),C’est là que notre étape avec la définition d’une propriété vide en tant que valeur par défaut a échoué. Maven vient d'y aller:
Enfin, la solution consiste à définir la valeur par défaut de manière dynamique. Cela peut être fait avec le plugin GMaven comme ceci:
<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>set-default-values</id>
<phase>initialize</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
project.properties.'surefire.argLine' = ''
</source>
</configuration>
</execution>
</executions>
</plugin>
Alors maintenant, Maven va:
Avec le profil actif, le fichier exec est généré, avec le profil non actif, la valeur par défaut vide est utilisée et la construction réussit.
Ma solution pour utiliser argLine dans le plugin maven-surefire en toute sécurité.
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>2.0</version>
<executions>
<execution>
<id>set-custom-arg-line</id>
<phase>validate</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
def argLine = project.properties['argLine'];
if (argLine == null) {
argLine = "";
}
project.properties.argLine = argLine;
</source>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<argLine>-Xmx1024m ${argLine}</argLine>
</configuration>
</plugin>
Mettez à jour le fichier POM.xml en tant que
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.7.201606060606</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.1</version>
<configuration>
<argLine>${argLine} -XX:PermSize=256m -XX:MaxPermSize=1048m</argLine>
</configuration>
</plugin>
ensuite, le plus important est de lancer le projet Maven avec les objectifs suivants: mvn jacoco: préparer le test de l'agent propre jacoco: rapport
Pour moi, la mise à niveau de la version 0.7.7.201606060606 à 0.7.9 a également corrigé ce problème.
Je devais ajouter explicitement la version à la ligne de commande (pas seulement au pom) car le serveur de construction continuait à utiliser l'ancienne version. Cela peut être fait comme suit:
org.jacoco:jacoco-maven-plugin:0.7.9:prepare-agent
au lieu de
org.jacoco:jacoco-maven-plugin:prepare-agent
Le site plugin jacoco (pour sonar) indique qu’argline doit être ajouté en tant que propriété. Pour moi, cela a également fonctionné avec le @{argLine}
dans les paramètres du plugin surefire.
J'ai ajouté un projet Maven/Java avec 1 classe de domaine avec les fonctionnalités suivantes:
J'ai gardé le projet aussi simple que possible. Le projet regroupe de nombreuses suggestions issues de ces articles et d’autres dans un exemple de projet. Merci aux contributeurs!
Le fichier readme donne une brève explication. Il explique comment exécuter un test utilisateur ou un test d'intégration avec Jacoco .
Prendre plaisir!