2009-09-14 14 views
29

Mam projekt Maven z 4 modułami - 3 z nich zawierają kod i niektóre testy (testowanie równa się i hashcode klas), podczas gdy czwarty moduł służy do testowania 3 innych modułów.cobertura na maven multi module project

Teraz chcę uruchomić narzędzie zasięgu kodu cobertura, aby uzyskać przegląd, które klasy są dobrze przetestowane, a które nie. Zrobiłem kilka badań na ten temat i wydaje się, że cobertura nie jest świadomy generowania prawidłowych procentów pokrycia kodu i pokrycia linii, jeśli niektóre testowane źródła znajdują się w innych modułach.

Przeczytałem kilka linków, takich jak SeamTestCoverageWithCobertura i Using the plugin Coverage within a multi-module Maven 2, ale musi to być gotowe rozwiązanie. Czy ktoś może zgłosić kilka nowych wskazówek na ten temat? A może są jakieś narzędzia, takie jak cobertura? Natknąłem się na emmę, ale to narzędzie nie oferuje zasięgu linii ...

Odpowiedz

19

Począwszy od wersji 2.6, nie jest agregatem opcja, która może być ustawiona na wartość true w pom dominującej:

<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 powinno to stać się zaakceptowaną odpowiedzią, ponieważ oba problemy wymienione w zaakceptowanej odpowiedzi są poprawione od 2.5. – r3nj1

+2

Można to również zrobić tylko z poziomu wiersza poleceń: 'mvn cobertura: cobertura -Dcobertura.aggregate = true -Dcobertura.report.format = xml' Możesz zmienić format raportu według własnego uznania. Zgodnie z repozytorium github repozytorium cobertura maven, ta funkcja jest dostępna [od 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

, ale nie wiem, dlaczego wynik pokrycia zawsze wynosi 0 w ten "zbiorczy" sposób – Stella

8

Zgodnie z MCOBERTURA-65, wtyczka maven cobertura nadal nie potrafi zagregować raportów dotyczących pod-modułów do wersji skonsolidowanej. Wykonano pewne prace, aby zaimplementować cel merge na wtyczce maven cobertura (patrz MCOBERTURA-33), ale ten kod nie został jeszcze uwzględniony w wtyczce. Nie testowałem łaty i nie mogę powiedzieć, czy warto spróbować.

W rezultacie wiele osób sugeruje korzystanie z maven dashboard plugin, ale ja osobiście trzymam się z dala od niego, ponieważ nie jest to bardzo satysfakcjonujące w dłuższej perspektywie i miałem do czynienia z wieloma problemami (problemy techniczne, utracone z historii, ...). Zamiast tego, gorąco polecam Sonar. Spójrz na Nemo, publiczną instancję ostatniej wersji Sonaru, aby zobaczyć wersję demonstracyjną tego narzędzia. Zobacz na przykład projekt Commons Digester i drill down of code coverage.

+0

tak sonar jest świadomy wielomodułowego pokrycia kodu? – pangratz

+1

Dlatego dodałem link do Nemo. Sprawdź na przykład http://nemo.sonarsource.org/project/index/commons-digester:commons-digester i drążenie: http://nemo.sonarsource.org/drilldown/measures/51834?metric=coverage –

+8

Sonar nie pokaże, że kod w pierwszych trzech modułach jest objęty kodem w czwartym module. Po prostu agreguje 4 całkowicie oddzielne i niekompletne raporty. –

0

mogę zaimplementować coś zupełnie podobny do tego, co trzeba, dzięki tej odpowiedzi: Maven - add dependency on artifact source

Właśnie dodałem <classifier>sources</classifier> i cobertura obejmuje zajęcia z zależnościami, jak również.

Pozdrawiam.

9

Nie mamy sonaru tutaj i teraz, nie możemy go zainstalować. Musiałem więc znaleźć obejście i go zdobyć. To rozwiązanie działa z prostym kodem mvn clean install -DrunCobertura=true w projekcie wielomodułowym. Trzeba tylko dodać ten profil do swojego super pom.xml swojego projektu, zdefiniować właściwość working.dir i powinna działać.

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

Co trzeba zrobić:

1.@process-classes -Instrument skompilowane klasy modułem.

2.@generate-test-sources -Merges plik z poprzednich modułów z utworzonego jednego modułu do uzyskania całkowitego pokrycia kodu .ser.

3.@test - Tworzy raport o pokryciu kodu. Powinien zostać wywołany w ostatnim module, ale ze względu na to, że ostatni moduł może się zmienić, zawsze nazywam go, a poprzednie raporty zostaną nadpisane. Jeśli używasz raportu w formacie xml (dla Jenkins), jest szybki, więc nie ma znaczenia.

2

Chciałbym bardzo podziękować Svenowi Oppermannowi za przesłanie jego rozwiązania w profilu runCobertura. To pomogło mi rozwiązać problem "jak uzyskać zbiorcze raporty pokrycia dla projektów wielomodułowych, gdy nie możesz być w stanie używać Sonaru.

Stworzyłem przykład, który pokazuje, jak tworzyć projekty wielomodułowego które produkują kod raportów pokrycia, które oceniają nie tylko zasięg testów jednostkowych (we wszystkich submodules), ale również pokrycie na testy integracyjne, które przynoszą zapasowa aplikacji jako .WAR W JETTY. Przykładem jest gospodarzem tutaj:

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

Przepis przytaczam jest dość wielokrotnego użytku, jeśli skopiować profil runCobertura wymienione poniżej (w. Na podstawie jednego świadczenia przez Sven)

Oto niektóre notatki które pomogą Ci korzystać z tego profilu:

* 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 oferuje ciekawe rozwiązanie, w którym raportowanie oprzyrządowanie i badanie odbywa się poprzez ant, ale wszystkie badania i zależnościach zarządzania poprzez mvn.

Sprawdź tutaj: thomassundberg wordpress

Oznacza to, że trzeba wykonać poniższe polecenia na poziomie dominującej w tej kolejności:

mvn clean compile 
ant instrument 
mvn test 
ant report 

Zintegrowanie tych kroków do sonar jest opisane przez Martijn Stelinga.

test-coverage-in-multi-module-projects

Powiązane problemy