cobertura на многомодульном проекте maven

У меня есть проект Maven с 4 модулями - 3 из них содержат код и некоторые тесты (тестирование равных и хэш-код классов), тогда как 4-й модуль предназначен для тестирования 3 других модулей.

теперь я хочу запустить инструмент покрытия кода cobertura, чтобы получить обзор, какие классы хорошо протестированы, а какие нет. Я провел некоторые исследования по этой теме, и кажется, что cobertura не знает о создании правильных процентов покрытия кода и покрытий строк, если некоторые источники которые испытаны расположены внутри другие модули.

Я прочитал некоторые ссылки, такие как SeamTestCoverageWithCobertura и использование покрытия плагина в многомодульном Maven 2 но должно быть какое-то решение. Может ли кто-нибудь сообщить о новых направлениях по этой теме? Или есть инструменты bether, такие как cobertura? Я наткнулся на Эмму, но этот инструмент не предлагает покрытие линии...

7 ответов


начиная с версии 2.6, есть агрегатный параметр, который может быть установлен в true в Родительском pom:

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

у нас нет сонара здесь и сейчас, мы не можем установить его. Поэтому мне пришлось найти обходной путь и найти его. Это решение работает с простым mvn clean install -DrunCobertura=true в многомодульном проекте. Вам нужно только добавить этот профиль в свой super pom.xml вашего проекта, определить working.dir свойство, и оно должно работать.

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

Что делать:

1. @process-classes-инструмент скомпилированные классы модуля.

2. @generate-test-sources-сливает the .ser файл из предыдущих модулей с созданным одним из этого модуля, чтобы получить полное покрытие кода.

3. @test-создает отчет о покрытии кода. Должен быть вызван в последнем модуле, но из-за того, что последний модуль может измениться, я вызываю его всегда и предыдущие отчеты будут перезаписаны. Если вы используете отчет в xml формат (для Дженкинса) это быстро, поэтому это не имеет значения.


по данным MCOBERTURA-65, плагин maven cobertura по-прежнему не знает, как объединить отчеты субмодулей в консолидированный. Проделана определенная работа по реализации merge target на плагине maven cobertura (см. MCOBERTURA-33), но этот код не был включен в плагин еще. Я сам не тестировал патч и не могу сказать, стоит ли пытаться.

вследствие этого многие люди действительно предлагают использовать maven плагин приборной панели но я бы лично держался подальше от него, поскольку он не очень удовлетворяет в долгосрочной перспективе, и я столкнулся с множеством проблем с ним (технические проблемы, потерянная история,...). Вместо Я горячо рекомендую эхолот. Взгляните на Немо, публичный экземпляр последней версии Sonar, для живой демонстрации этого инструмента. См., например,Община Digester и детализация кода покрытие.


есть несколько плагинов, которые агрегируют отчеты Cobertura (и другие). Проверьте эхолот и XRadar Плагины. Существует также плагин приборной панели, но это немного неуклюжим.

Fwiw Эмма делает освещение строка.


мне бы очень хотелось поблагодарить Свена Оррегмаппбыл для представления своего решения профиля runCobertura. Это помогло я решаю вопрос: "как вы получаете отчеты о совокупном покрытии для многомодульных проектов, когда вас может не быть возможность использования сонара.

Я создал пример, который демонстрирует, как создавать многомодульные проекты, которые создают отчеты о покрытии кода, которые оценивают не только покрытие модульных тестов (во всех подмодулях), но и покрытие интеграционных тестов, которые ПРИНОСИТЬ ПОДНИМИТЕ ВАШЕ ПРИЛОЖЕНИЕ КАК A .ВОЙНА НА ПРИСТАНИ. Пример размещен здесь:

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

рецепт, который я предоставляю, довольно повторно используется, если вы скопируете профиль runCobertura, указанный ниже (на основе предоставьте Sven.)

вот некоторые заметки, которые помогут вам использовать этот профиль:

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

Thomas Sundberg предлагает интересное решение, в котором приборы и отчеты об испытаниях выполняются через ant, но все тестирование и управление зависимостями через mvn.

Регистрация Здесь: томассундберг wordpress

Это означает, что вы должны выполнить приведенные ниже команды на родительском уровне в следующем порядке:

mvn clean compile
ant instrument
mvn test
ant report

интеграция этих шагов в sonar описывается Martijn Stelinga.

test-coverage-in-multi-module-проекты


Я мог бы реализовать что-то очень похожее на то, что вам нужно, благодаря этому ответу: Maven-добавить зависимость от источника артефакта

Я только что добавил <classifier>sources</classifier> и cobertura также включает классы из зависимостей.

С уважением.