web-dev-qa-db-fra.com

Vous ne pouvez pas utiliser jacoco JVM args et JVM args se réunissent dans maven

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

57
John Q Citizen

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.

37
Will Gage

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?

34
Kaszaq

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

16
Sebastian

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

11
Faisal Feroz

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

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:

  1. avec impatience (avant que tout objectif soit exécuté) sont remplacés statique propriétés (définies dans la section properties de POM et probablement aussi settings.xml),
  2. paresseusement (avant chaque exécution) sont remplacés dynamique propriétés.

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:

  1. désireux de remplacer la valeur par défaut (blanc)
  2. JaCoCo définit la valeur dynamique
  3. remplacement paresseux des valeurs dynamiques (rien à remplacer maintenant, déjà utilisé la valeur vide)

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:

  1. désireux de remplacer les propriétés statiques
  2. GMaven définit de manière dynamique la valeur par défaut (si le profil est actif)
  3. JaCoCo définit la valeur dynamique
  4. Surefire fonctionne avec argLine correctement défini

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.

4
Mrkvozrout

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

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

1
sachit s

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.

1
Thirler

J'ai ajouté un projet Maven/Java avec 1 classe de domaine avec les fonctionnalités suivantes:

  • Test unitaire ou d'intégration avec les plugins Surefire et Failsafe.
  • Findbugs.
  • Testez la couverture via Jacoco .

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!

0
tjm1706