2009-09-14 8 views
29

Ich habe ein Maven Projekt mit 4 Modulen - 3 von ihnen enthalten Code und einige Tests (testing equals und hashcode der Klassen), während das vierte Modul zum Testen der 3 anderen Module dient.cobertura on maven multi Modul Projekt

Jetzt möchte ich das Cobertura Code Coverage Tool ausführen, um einen Überblick zu bekommen, welche Klassen gut getestet wurden und welche nicht. Ich habe einige Untersuchungen zu diesem Thema durchgeführt, und es scheint, dass Cobertura nicht weiß, dass die richtigen Prozentzahlen für die Codeabdeckung und die Zeilenabdeckung generiert werden, wenn einige Quellen, die getestet werden, sich in anderen Modulen befinden.

Ich habe einige Links wie SeamTestCoverageWithCobertura und Using the plugin Coverage within a multi-module Maven 2 gelesen, aber es muss eine Out of the Box-Lösung sein. Kann jemand neue Anweisungen zu diesem Thema geben? Oder gibt es Werkzeuge wie Cobertura? Ich bin über Emma gestolpert, aber dieses Werkzeug bietet keine Leitungsabdeckung ...

Antwort

19

Ab Version 2.6 gibt es ein Aggregat Option, die auf true in der übergeordneten pom gesetzt werden können:

<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

IMHO sollte dies die akzeptierte Antwort werden, da beide in der angenommenen Antwort genannten Probleme seit 2.5 behoben sind. – r3nj1

+2

Dies kann auch nur über die Befehlszeile erfolgen: 'mvn cobertura: cobertura -Dcobertura.aggregate = true -Dcobertura.report.format = xml' Sie können das Berichtsformat nach Belieben ändern. Nach dem Github Repo des Cobertura Maven Plugins ist diese Funktion verfügbar [seit v2.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

aber nicht sicher, warum die Abdeckung Ergebnis immer 0 durch diese "aggregierte" Art und Weise – Stella

3

Es gibt ein paar Plugins, die Cobertura (und andere) Berichte aggregieren. Überprüfen Sie die sonar und XRadar Plugins. Es gibt auch die dashboard plugin, aber es ist ein bisschen klobig.

FWIW Emma tut line coverage.

8

Laut MCOBERTURA-65 weiß das Maven Cobertura-Plugin immer noch nicht, wie Berichte von Untermodulen zu einem konsolidierten zusammengefasst werden. Einige Arbeit wurde getan, um ein merge Ziel auf dem Maven Cobertura Plugin zu implementieren (siehe MCOBERTURA-33), aber dieser Code wurde noch nicht in das Plugin aufgenommen. Ich habe den Patch nicht selbst getestet und kann nicht sagen, ob es einen Versuch wert ist.

In der Konsequenz empfehlen viele Leute tatsächlich, das maven dashboard plugin zu verwenden, aber ich würde persönlich weit weg davon bleiben, da es auf lange Sicht nicht sehr befriedigend ist und ich viele Probleme damit konfrontiert habe (technische Probleme, Geschichtsverlust, ...). Stattdessen, Ich empfehle wärmstens Sonar. Werfen Sie einen Blick auf Nemo, eine öffentliche Instanz der letzten Version von Sonar, für eine Live-Demo dieses Tools. Siehe zum Beispiel das Projekt Commons Digester und die drill down of code coverage.

+0

so Sonar ist sich dessen bewusst mehrmoduligen Codeabdeckung? – pangratz

+1

Deshalb habe ich einen Link zu Nemo hinzugefügt. Überprüfen Sie zum Beispiel http://nemo.sonarsource.org/project/index/commons-digester:commons-digester und den Drilldown: http://nemo.sonarsource.org/drilldown/measures/51834?metric=coverage –

+8

Sonar wird nicht zeigen, dass Code in den ersten drei Modulen durch Code im vierten Modul abgedeckt wird. Es aggregiert einfach die 4 vollständig getrennten und unvollständigen Berichte. –

0

ich etwas ganz ähnlich implementieren könnte, was Sie dank dieser Antwort brauchen: Maven - add dependency on artifact source

Habe ich nur noch <classifier>sources</classifier> und cobertura Klassen von Abhängigkeiten enthält auch.

Grüße.

9

Wir haben kein Sonar hier und jetzt, wir können es nicht installieren. Also musste ich einen Workaround finden und bekam einen. Diese Lösung arbeitet mit einem einfachen mvn clean install -DrunCobertura=true in einem Multi-Modul-Projekt. Sie müssen dieses Profil nur zu Ihrem Ihres Projekts hinzufügen, die Eigenschaft working.dir definieren und es sollte funktionieren.

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

Was es tut:

1.@process-classes Gerätefunktionen- die kompilierten Klassen des Moduls.

2.@generate-test-sources -Merges die .ser Datei aus früheren Modulen mit dem erstellten eines dieses Moduls die komplette Codeabdeckung zu erhalten.

3.@test - Erstellt den Code-Coverage-Bericht. Sollte im letzten Modul aufgerufen werden, aber da sich das letzte Modul ändern kann, rufe ich es immer an und die vorherigen Berichte werden überschrieben. Wenn Sie den Bericht in xml Format (für Jenkins) verwenden, ist es schnell, also spielt es keine Rolle.

2

Ich möchte Sven Oppermann sehr herzlich für die Einreichung seiner runCobertura-Profillösung danken. Dies half mir die Frage zu lösen "Wie erhalten Sie Aggregat Berichterstattung Berichte für Multi-Modul-Projekte, wenn Sie nicht Sonar verwenden können.

Ich habe ein Beispiel geschaffen, das zeigt, wie Multi-Modul-Projekte erstellen, die Code-Coverage-Berichte erstellen, das nicht nur Einheit Testabdeckung (in allen Submodule), aber auch Berichterstattung über Integrationstests zu bewerten, die als UP YOUR ANWENDUNG BRINGEN .WAR IN JETTY. Das Beispiel ist hier gehostet:

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

Das Rezept, das ich die Bereitstellung bin ziemlich wiederverwendbarer, wenn Sie die runCobertura Profil kopieren unten aufgeführt (. Basierend auf der einen von Sven liefern)

Hier sind einige Hinweise die dieses Profil helfen Sie verwenden:

* 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 bietet eine interessante Lösung, in der Mess- und Prüftechnik Berichterstattung über ant getan wird, aber alle Tests und Abhängigkeitsmanagement über mvn.

prüfen: thomassundberg wordpress

Es bedeutet, dass Sie die folgenden Befehle auf der übergeordneten Ebene in dieser Reihenfolge auszuführen haben:

mvn clean compile 
ant instrument 
mvn test 
ant report 

diese Schritte in sonar Integration von Martijn Stelinga beschrieben.

test-coverage-in-multi-module-projects