2009-09-14 9 views
29

J'ai un projet Maven avec 4 modules - 3 d'entre eux contiennent du code et quelques tests (tests égaux et hash des classes) tandis que le 4ème module est pour tester les 3 autres modules.cobertura sur le projet multi-module maven

Maintenant, je veux lancer l'outil de couverture de code cobertura pour avoir une vue d'ensemble des classes qui sont bien testées et celles qui ne le sont pas. J'ai fait des recherches sur ce sujet et il semble que Cobertura ne soit pas conscient de générer les bons pourcentages de couverture de code et de couverture de ligne, si certaines sources testées se trouvent dans d'autres modules.

J'ai lu quelques liens comme SeamTestCoverageWithCobertura et Using the plugin Coverage within a multi-module Maven 2 mais il doit y avoir une solution prête à l'emploi. Quelqu'un peut-il signaler de nouvelles directions sur ce sujet? Ou y a-t-il des outils comme cobertura? Je suis tombé sur emma mais cet outil n'offre pas de couverture de ligne ...

Répondre

19

de la version 2.6, il existe une option globale qui peut être définie sur true dans la pom-mère:

<reporting> 
<plugins> 
    <plugin> 
    <groupId>org.codehaus.mojo</groupId> 
    <artifactId>cobertura-maven-plugin</artifactId> 
    <version>2.6</version> 
    <configuration> 
     <outputDirectory>./target/tmpCobertura</outputDirectory> 
     <formats> 
      <format>html</format> 
     </formats> 
     <aggregate>true</aggregate> 
    </configuration> 
    </plugin> 
</plugins> 
</reporting> 
+2

À mon humble avis ceci devrait devenir la réponse acceptée puisque les deux problèmes mentionnés dans la réponse acceptée sont fixes depuis 2.5. – r3nj1

+2

Cela peut aussi se faire via la ligne de commande uniquement: 'mvn cobertura: cobertura -Dcobertura.aggregate = true -Dcobertura.report.format = xml' Vous pouvez modifier le format du rapport que vous le souhaitez. Selon le repo github du plugin cobertura maven, cette fonctionnalité est disponible [depuis la version 2.5] (https://github.com/mojohaus/cobertura-maven-plugin/blob/master/src/main/java/org/codehaus/mojo/cobertura/CoberturaReportMojo.java # L126) (commit [64a8823] (https://github.com/mojohaus/cobertura-maven-plugin/commit/64a8823866b4c8be74a44383162088d616c65185#diff-e4171be1b77f9a9b331e21a0661c1433R126)). – clapsus

+0

mais je ne sais pas pourquoi le résultat de la couverture est toujours égal à 0 par cette méthode "agrégée" – Stella

3

Il y a quelques plugins qui agrègent les rapports Cobertura (et autres). Découvrez les plugins sonar et XRadar. Il y a aussi le dashboard plugin, mais c'est un peu maladroit.

FWIW Emma fait line coverage.

8

Selon le MCOBERTURA-65, le plugin maven cobertura ne sait toujours pas comment agréger les rapports de sous-modules dans un consolidé. Un certain travail a été fait pour implémenter une cible merge sur le plugin maven cobertura (voir MCOBERTURA-33) mais ce code n'a pas encore été inclus dans le plugin. Je n'ai pas testé le patch moi-même et je ne peux pas dire si ça vaut le coup d'essayer. En conséquence, beaucoup de gens suggèrent en effet d'utiliser le maven dashboard plugin mais je resterais personnellement loin de lui car il n'est pas très satisfaisant sur le long terme et j'ai fait face à beaucoup de problèmes avec lui (problèmes techniques, perdu de l'histoire, ...). Au lieu de cela, je recommande chaudement Sonar. Jetez un oeil à Nemo, une instance publique de la dernière version de Sonar, pour une démo en direct de cet outil. Voir par exemple le projet Commons Digester et le drill down of code coverage.

+0

si sonar est conscient de la couverture de code multi-module? – pangratz

+1

C'est pourquoi j'ai ajouté un lien vers Nemo. Vérifiez par exemple http://nemo.sonarsource.org/project/index/commons-digester:commons-digester et l'analyse descendante: http://nemo.sonarsource.org/drilldown/measures/51834?metric=coverage –

+8

Sonar ne montrera pas que le code dans les trois premiers modules est couvert par le code dans le quatrième module. Il regroupe simplement les 4 rapports complètement séparés et incomplets. –

0

je pourrais mettre en œuvre quelque chose de tout à fait semblable à ce que vous avez besoin grâce à cette réponse: Maven - add dependency on artifact source

Je viens d'ajouter <classifier>sources</classifier> et cobertura comprend des classes de dépendances aussi bien.

Cordialement.

9

Nous n'avons pas de sonar ici et maintenant, nous ne pouvons pas l'installer. J'ai donc dû trouver une solution de contournement et en avoir un. Cette solution fonctionne avec un simple mvn clean install -DrunCobertura=true dans un projet multi-modules. Vous avez seulement besoin d'ajouter ce profil à votre super pom.xml de votre projet, définissez la propriété working.dir et cela devrait fonctionner.

<profile> 
    <id>runCobertura</id> 
    <activation> 
     <property> 
      <name>runCobertura</name> 
      <value>true</value> 
     </property> 
    </activation> 
    <properties> 
     <cobertura.format>html</cobertura.format> 
     <cobertura.working.dir>${working.dir}/${project.version}/cobertura</cobertura.working.dir> 
     <cobertura.complete.ser.file>${cobertura.working.dir}/complete.ser</cobertura.complete.ser.file> 
    </properties> 
    <build> 
     <plugins> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-clean-plugin</artifactId> 
       <version>2.4.1</version> 
       <inherited>false</inherited> 
       <configuration> 
        <filesets> 
         <fileset> 
          <directory>.</directory> 
          <includes> 
           <include>cobertura.ser</include> 
          </includes> 
         </fileset> 
         <fileset> 
           <directory>${cobertura.working.dir}</directory> 
          </fileset> 
        </filesets> 
       </configuration> 
      </plugin> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-antrun-plugin</artifactId> 
       <version>1.7</version> 
       <executions> 
        <execution> 
         <id>cobertura-Instrument</id> 
         <phase>process-classes</phase> 
         <goals> 
          <goal>run</goal> 
         </goals> 
         <configuration> 
          <target> 
           <taskdef resource="tasks.properties"/> 
           <taskdef resource="net/sf/antcontrib/antcontrib.properties"/> 
           <if> 
            <available file="${project.build.outputDirectory}"/> 
            <then> 
             <cobertura-instrument> 
              <fileset dir="${project.build.outputDirectory}"> 
               <include name="**/*.class"/> 
              </fileset> 
             </cobertura-instrument> 
            </then> 
           </if> 
          </target> 
         </configuration> 
        </execution> 
        <execution> 
         <id>cobertura-createCombinedSerFile</id> 
         <phase>generate-test-sources</phase> 
         <goals> 
          <goal>run</goal> 
         </goals> 
         <configuration> 
          <target> 
           <taskdef resource="tasks.properties"/> 
           <taskdef resource="net/sf/antcontrib/antcontrib.properties"/> 
           <if> 
            <available file="${cobertura.complete.ser.file}"/> 
            <then> 
             <cobertura-merge datafile="${basedir}/tmp.ser"> 
              <fileset file="${cobertura.complete.ser.file}"/> 
              <fileset file="${basedir}/cobertura.ser"/> 
             </cobertura-merge> 
             <move file="${basedir}/tmp.ser" tofile="${basedir}/cobertura.ser"/> 
            </then> 
           </if> 
          </target> 
         </configuration> 
        </execution> 
        <execution> 
         <id>cobertura-copyResultSerFileAndSources</id> 
         <phase>test</phase> 
         <goals> 
          <goal>run</goal> 
         </goals> 
         <configuration> 
          <target> 
           <taskdef resource="tasks.properties"/> 
           <taskdef resource="net/sf/antcontrib/antcontrib.properties"/> 
           <if> 
            <available file="${basedir}/cobertura.ser"/> 
            <then> 
             <move file="${basedir}/cobertura.ser" tofile="${cobertura.complete.ser.file}"/> 
             <mkdir dir="${cobertura.working.dir}/source"/> 
             <if> 
              <available file="${basedir}/src/main/java"/> 
              <then> 
               <copy todir="${cobertura.working.dir}/source"> 
                <fileset dir="src/main/java"> 
                 <include name="**/*.java"/> 
                </fileset> 
               </copy> 
              </then> 
             </if> 
             <cobertura-report datafile="${cobertura.complete.ser.file}" format="${cobertura.format}" destdir="${cobertura.working.dir}/report"> 
              <fileset dir="${cobertura.working.dir}/source"/> 
             </cobertura-report> 
            </then> 
           </if> 
          </target> 
         </configuration> 
        </execution> 
       </executions> 
       <dependencies> 
        <dependency> 
         <groupId>net.sourceforge.cobertura</groupId> 
         <artifactId>cobertura</artifactId> 
         <version>1.9.4.1</version> 
        </dependency> 
        <dependency> 
         <groupId>ant-contrib</groupId> 
         <artifactId>ant-contrib</artifactId> 
         <version>20020829</version> 
        </dependency> 
       </dependencies> 
      </plugin> 
     </plugins> 
    </build> 
    <dependencies> 
     <dependency> 
      <groupId>net.sourceforge.cobertura</groupId> 
      <artifactId>cobertura</artifactId> 
      <version>1.9.4.1</version> 
      <scope>test</scope> 
     </dependency> 
    </dependencies> 
</profile> 

Que fait-il:

1.@process-classes -instrument les classes compilées du module.

2.@generate-test-sources -Merges le fichier .ser des modules précédents avec la création d'un de ce module pour obtenir la couverture de code complet.

3.@test -Crée le rapport de couverture de code. Doit être appelé dans le dernier module, mais en raison du fait que le dernier module peut changer, je l'appelle toujours et les rapports précédents seront écrasés. Si vous utilisez le rapport au format xml (pour Jenkins) c'est rapide, donc ce n'est pas grave.

2

Je voudrais vraiment remercier Sven Oppermann pour avoir soumis sa solution de profil runCobertura. Cela m'a aidé à résoudre la question de savoir comment obtenir des rapports de couverture agrégés pour les projets multi-modules lorsque vous ne pouvez pas utiliser le Sonar.

J'ai créé un exemple qui montre comment créer des projets multi-modules qui produisent des rapports de couverture de code qui évaluent non seulement la couverture de test unitaire (dans tous les sous-modules) mais aussi la couverture des tests d'intégration. .WAR EN JETTY. L'exemple est hébergé ici:

 http://dl.dropbox.com/u/9940067/code/multi-module-cobertura.zip 

La recette que je suis fournirai est assez réutilisable si vous copiez le profil runCobertura ci-dessous (. Basé sur celui fournir par Sven)

Voici quelques notes qui vous aidera à utiliser ce profil:

* the integration test module that launches jetty (and defines tests that run against 
    the production .war) must either be named web-test-driver-for-code-coverage, or you 
    must modify the <if> statements in the runCobertura configuration block. 

* your coverage reports will appear wherever you set your <working.dir> variable 

* you MUST include 'clean' on the command line when you run your build for code coverage. 'clean' 
    will blow away prior cobertura.ser files, 
    which if left lurking around can cause very confusing reports to be 
    generated (a sign you need to 'clean' is that the reports show 
    100% coverage for everything, including stuff you know is never called. 

      mvn -PrunCobertura clean install  # gives you the aggregate reports. 



* the module web-test-driver-for-code-coverage defines a servlet context listener that explicitly flushes the cobertura metrics to disk 
    when the web server shuts down. Supposedly the container is supposed to do this automatically, but that didn't work for me, so 
    I had to hook in the explicit call to flush out the metrics. 

* the integration tests are done in groovy because i based this on some maven project skeletons that already used groovy. 
    Sorry for the added clutter, but it does show you how to do your tests in groovy (which is highly recommended anyway.) 

* Note that when you compile with the runCobertura profile all of your artifacts are created with cobertura instrumentation, even your 
    .war file. You NEVER want to let this get out in production of course (for one thing it would run realllll slow.) I have not 
    yet figured out a food way to get the artifacts to rename themselves so that the 'cobertura-ness' is obvious. 



    <profiles> 
    <profile> 
     <id>runCobertura</id> 
     <activation> 
      <property> 
       <name>runCobertura</name> 
       <value>true</value> 
      </property> 
     </activation> 
     <properties> 
      <cobertura.format>html</cobertura.format> 
      <working.dir>/tmp</working.dir> 
      <cobertura.working.dir>${working.dir}/${project.version}/cobertura</cobertura.working.dir> 
      <cobertura.complete.ser.file>${cobertura.working.dir}/complete.ser</cobertura.complete.ser.file> 

      <!-- scope which determines whether or not cobertura is included in .war file: overriden here --> 
      <cobertura.dependency.scope>compile</cobertura.dependency.scope> 
     </properties> 
     <build> 
      <plugins> 
       <plugin> 
        <groupId>org.apache.maven.plugins</groupId> 
        <artifactId>maven-clean-plugin</artifactId> 
        <version>2.4.1</version> 
        <inherited>false</inherited> 
        <configuration> 
         <filesets> 
          <fileset> 
           <directory>.</directory> 
           <includes> 
            <include>**/cobertura.ser</include> 
           </includes> 
          </fileset> 
          <fileset> 
            <directory>${cobertura.working.dir}</directory> 
           </fileset> 
         </filesets> 
        </configuration> 
       </plugin> 




       <plugin> 
        <groupId>org.apache.maven.plugins</groupId> 
        <artifactId>maven-antrun-plugin</artifactId> 
        <version>1.7</version> 
        <executions> 
         <execution> 
          <id>cobertura-Instrument</id> 
          <phase>process-classes</phase> 
          <goals> 
           <goal>run</goal> 
          </goals> 
          <configuration> 
           <target> 
            <taskdef resource="tasks.properties"/> 
            <taskdef resource="net/sf/antcontrib/antcontrib.properties"/> 
            <echo message="::PROCESS CLASSES: ${artifactId}"/> 

            <if> 
             <equals arg1="${artifactId}" arg2="web-test-driver-for-code-coverage" /> 
             <then> 
              <echo message="::SKIPPING PHASE for integration test"/> 
             </then> 
             <else> 
              <if> 
               <available file="${project.build.outputDirectory}"/> 
               <then> 
                <echo message="::BEFORE INSTRUMENT"/> 
                <cobertura-instrument> 
                 <fileset dir="${project.build.outputDirectory}"> 
                  <include name="**/*.class"/> 
                 </fileset> 
                </cobertura-instrument> 
               </then> 
              </if> 
             </else> 
            </if> 


           </target> 
          </configuration> 
         </execution> 
         <execution> 
          <id>cobertura-createCombinedSerFile</id> 
          <phase>generate-test-sources</phase> 
          <goals> 
           <goal>run</goal> 
          </goals> 
          <configuration> 
           <target> 
            <taskdef resource="tasks.properties"/> 
            <taskdef resource="net/sf/antcontrib/antcontrib.properties"/> 
            <echo message=":::generate-test-sources"/> 


            <if> 
             <equals arg1="${artifactId}" arg2="web-test-driver-for-code-coverage" /> 
             <then> 
              <echo message="::SHORT CIRCUIT COMBINE PHASE for integration test"/> 
              <echo message="source - ${cobertura.complete.ser.file} dest - ${basedir}/cobertura.ser"/> 
              <copy file="${cobertura.complete.ser.file}" tofile="${basedir}/cobertura.ser"/> 
             </then> 
             <else> 
              <if> 
               <available file="${basedir}/cobertura.ser"/> 
               <then> 
                <echo message="::: Is available ${basedir}/cobertura.ser"/> 
               </then> 
              </if> 

              <if> 
               <available file="${cobertura.complete.ser.file}"/> 
               <then> 
                <echo message="before merge1"/> 
                <cobertura-merge datafile="${basedir}/tmp.ser"> 
                 <fileset file="${cobertura.complete.ser.file}"/> 
                 <fileset file="${basedir}/cobertura.ser"/> 
                </cobertura-merge> 
                <echo message="move temp.ser to ${basedir}/cobertura.ser"/> 
                <move file="${basedir}/tmp.ser" tofile="${basedir}/cobertura.ser"/> 
               </then> 
              </if> 
             </else> 
            </if> 
           </target> 
          </configuration> 
         </execution> 
         <execution> 
          <id>cobertura-copyResultSerFileAndSources</id> 
          <phase>verify</phase> 
          <goals> 
           <goal>run</goal> 
          </goals> 
          <configuration> 
           <target> 
            <taskdef resource="tasks.properties"/> 
            <taskdef resource="net/sf/antcontrib/antcontrib.properties"/> 

            <echo message=":::copyResultSerFileAndSources -beforeIf"/> 
            <if> 
             <available file="${basedir}/cobertura.ser"/> 
             <then> 
              <echo message="move1"/> 
              <move file="${basedir}/cobertura.ser" tofile="${cobertura.complete.ser.file}"/> 
              <mkdir dir="${cobertura.working.dir}/source"/> 
              <if> 
               <available file="${basedir}/src/main/java"/> 
               <then> 
                <copy todir="${cobertura.working.dir}/source"> 
                 <fileset dir="src/main/java"> 
                  <include name="**/*.java"/> 
                 </fileset> 
                </copy> 
               </then> 
              </if> 
              <echo message="runreport"/> 
              <cobertura-report datafile="${cobertura.complete.ser.file}" format="${cobertura.format}" destdir="${cobertura.working.dir}/report"> 
               <fileset dir="${cobertura.working.dir}/source"/> 
              </cobertura-report> 
             </then> 
            </if> 
           </target> 
          </configuration> 
         </execution> 
        </executions> 
        <dependencies> 
         <dependency> 
          <groupId>net.sourceforge.cobertura</groupId> 
          <artifactId>cobertura</artifactId> 
          <version>1.9.4.1</version> 
         </dependency> 
         <dependency> 
          <groupId>ant-contrib</groupId> 
          <artifactId>ant-contrib</artifactId> 
          <version>20020829</version> 
         </dependency> 
        </dependencies> 
       </plugin> 
      </plugins> 
     </build> 
     <dependencies> 
      <dependency> 
       <groupId>net.sourceforge.cobertura</groupId> 
       <artifactId>cobertura</artifactId> 
       <version>1.9.4.1</version> 
      </dependency> 
     </dependencies> 
    </profile> 
    </profiles> 
1

Thomas Sundberg offre une solution intéressante dans laquelle les rapports d'instrumentation et d'essai se fait via ant, mais tous les tests et gestion des dépendances via mvn.

Venez voir: thomassundberg wordpress

Cela signifie que vous devez exécuter les commandes ci-dessous au niveau des parents dans cet ordre:

mvn clean compile 
ant instrument 
mvn test 
ant report 

L'intégration de ces étapes dans sonar est décrite par Martijn Stelinga.

test-coverage-in-multi-module-projects

Questions connexes