2009-09-14 19 views
29

Tengo un proyecto Maven con 4 módulos - 3 de ellos contienen código y algunas pruebas (pruebas iguales y hashcode de las clases) mientras que el 4º módulo es para probar los otros 3 módulos.cobertura en el proyecto de varios módulos de maven

Ahora quiero ejecutar la herramienta de cobertura de código de cobertura para obtener una visión general de qué clases están bien probadas y cuáles no. Hice algunas investigaciones sobre ese tema y parece que cobertura no está consciente de generar los porcentajes de cobertura de código correctos y las coberturas de línea, si algunas fuentes que se prueban están ubicadas dentro de otros módulos.

He leído algunos enlaces como SeamTestCoverageWithCobertura y Using the plugin Coverage within a multi-module Maven 2, pero tiene que haber una solución inmediata. ¿Alguien puede informar algunas nuevas direcciones sobre este tema? ¿O hay otras herramientas como cobertura? Me encontré con emma pero esta herramienta no ofrece cobertura de línea ...

Respuesta

19

partir de la versión 2.6, hay una opción agregada que se puede establecer en true en el pom padres:

<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

En mi humilde opinión esto debería ser la respuesta aceptada ya que ambos problemas mencionados en la respuesta aceptada son fijos desde 2.5. – r3nj1

+2

Esto también se puede hacer a través de la línea de comando: 'mvn cobertura: cobertura -Dcobertura.aggregate = true -Dcobertura.report.format = xml' Puede cambiar el formato del informe como lo desee. De acuerdo con el repositorio github del plugin de cobertura maven, esta función está disponible [desde v2.5] (https://github.com/mojohaus/cobertura-maven-plugin/blob/master/src/main/java/org/codehaus/mojo/cobertura/CoberturaReportMojo.java # L126) (confirmar [64a8823] (https://github.com/mojohaus/cobertura-maven-plugin/commit/64a8823866b4c8be74a44383162088d616c65185#diff-e4171be1b77f9a9b331e21a0661c1433R126)). – clapsus

+0

pero no estoy seguro por qué el resultado de la cobertura siempre es 0 por este método "agregado" – Stella

8

De acuerdo con MCOBERTURA-65, el plugin maven cobertura aún no sabe cómo agregar informes de submódulos en uno consolidado. Se ha realizado algo de trabajo para implementar un objetivo merge en el plugin maven cobertura (consulte MCOBERTURA-33) pero este código aún no se ha incluido en el complemento. No probé el parche y no puedo decir si vale la pena intentarlo.

En consecuencia, mucha gente sugiere utilizar el maven dashboard plugin, pero yo personalmente me mantendría lejos de él, ya que no es muy satisfactorio a largo plazo y tuve muchos problemas con él (problemas técnicos, perdido de la historia, ...). En cambio, Recomiendo encarecidamente Sonar. Eche un vistazo a Nemo, una instancia pública de la última versión de Sonar, para una demostración en vivo de esta herramienta. Ver por ejemplo el proyecto Commons Digester y el drill down of code coverage.

+0

modo sonar es consciente de cobertura de código multi-módulo? – pangratz

+1

Es por eso que agregué un enlace a Nemo. Consulte, por ejemplo, http://nemo.sonarsource.org/project/index/commons- digester:commons- digester y la información detallada: http://nemo.sonarsource.org/drilldown/measures/51834?metric=coverage –

+8

Sonar no mostrará que el código en los primeros tres módulos está cubierto por código en el cuarto módulo. Simplemente agrega los 4 informes completamente separados e incompletos. –

0

pude poner en práctica algo bastante similar a lo que necesita gracias a esta respuesta: Maven - add dependency on artifact source

simplemente he añadido <classifier>sources</classifier> y Cobertura incluye clases de dependencias.

Atentamente.

9

No tenemos sonar aquí y ahora, no podemos instalarlo. Así que tuve que encontrar una solución y obtuve una. Esta solución funciona con un simple mvn clean install -DrunCobertura=true en un proyecto de varios módulos. Solo necesita agregar este perfil a su super pom.xml de su proyecto, defina la propiedad working.dir y debería funcionar.

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

¿Qué hace:

1.@process-classes -Instrumento las clases compiladas del módulo.

2.@generate-test-sources -Merges el archivo .ser de los módulos anteriores con el creado de este módulo para obtener la cobertura de código completa.

3.@test -Crea el informe de cobertura del código. Debería llamarse en el último módulo, pero debido a que el último módulo puede cambiar, lo llamo siempre y los informes anteriores se sobrescribirán. Si utiliza el informe en formato xml (para Jenkins) es rápido, por lo que no importa.

2

Me gustaría agradecer a Sven Oppermann por enviar su solución de perfil runCobertura. Esto ayudó a a resolver la pregunta de '¿cómo se obtienen informes de cobertura agregados para proyectos de múltiples módulos cuando es posible que no sea capaz de utilizar Sonar.

He creado un ejemplo que muestra cómo crear proyectos de varios módulos que producen informes de cobertura de código para evaluar no sólo la cobertura de prueba de unidad (en todos los submódulos), sino también la cobertura de las pruebas de integración que traen SU APLICACIÓN COMO .WAR EN JETTY. El ejemplo está alojado aquí:

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

La receta que proporciono es bastante reutilizable si copia el perfil runCobertura se enumeran a continuación (. Basado en el proporcionan por Sven)

Estas son algunas notas lo que le ayudará a utilizar este perfil:

* 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 ofrece una solución interesante en el que la instrumentación y la prueba de informes se realiza a través ant, pero toda la gestión de las pruebas y la dependencia a través mvn.

marque aquí: thomassundberg wordpress

Esto significa que usted tiene que ejecutar los siguientes comandos en el nivel primario, en este orden:

mvn clean compile 
ant instrument 
mvn test 
ant report 

La integración de estos pasos en sonar es descrito por Martijn Stelinga.

test-coverage-in-multi-module-projects

Cuestiones relacionadas