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

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

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

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


person pangratz    schedule 14.09.2009    source источник


Ответы (7)


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

<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>
person Martin    schedule 16.08.2013
comment
ИМХО, это должен стать принятым ответом, поскольку обе проблемы, упомянутые в принятом ответе, исправлены с версии 2.5. - person stdll; 05.05.2015
comment
Это также можно сделать только через командную строку: mvn cobertura:cobertura -Dcobertura.aggregate=true -Dcobertura.report.format=xml Вы можете изменить формат отчета по своему желанию. Согласно репозиторию github плагина cobertura maven, эта функция доступна начиная с версии 2.5 (фиксация 64a8823). - person clapsus; 27.07.2016
comment
но не уверен, почему результат покрытия всегда 0 этим совокупным способом - person Stella; 30.09.2016
comment
Даже имея ‹aggregate› true ‹/aggregate›, я не получаю сводный отчет. Что еще я должен проверить? Фактически, в моем проекте используется версия 2.7 Cobertura, которая утверждает, что по умолчанию решает проблему с многомодульным проектом. - person Dish; 07.03.2018
comment
Отсутствие совокупного охвата в cobertura версии 2.7 с aggregate = true. Кто-нибудь знает, что не так с настройкой? - person JITHIN_PATHROSE; 01.10.2018

У нас нет эхолота здесь и сейчас, мы не можем его установить. Поэтому мне пришлось найти обходной путь и получил его. Это решение работает с простым 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 - объединяет .ser файл из предыдущих модулей с созданным в этом модуле, чтобы получить полное покрытие кода.

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

person Sven Oppermann    schedule 04.04.2012

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

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

person Pascal Thivent    schedule 14.09.2009
comment
Вот почему я добавил ссылку на Nemo. Например, проверьте nemo.sonarsource.org/project/index/ и детализация: nemo.sonarsource.org/drilldown/measures/51834? метрика = покрытие - person Pascal Thivent; 14.09.2009
comment
Сонар не покажет, что код в первых трех модулях покрывается кодом четвертого модуля. Он просто объединяет 4 полностью отдельных и неполных отчета. - person Craig P. Motlin; 10.03.2010
comment
Насколько я понимаю, Sonar не позволяет вам контролировать покрытие кода по пороговому значению как часть жизненного цикла сборки. - person yegor256; 30.12.2010

Есть несколько плагинов, которые собирают отчеты Cobertura (и другие). Ознакомьтесь с сонаром и плагины XRadar. Также существует плагин панели управления, но он немного неуклюжий.

FWIW Эмма действительно выполняет покрытие линии.

person Rich Seller    schedule 14.09.2009

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

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

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

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

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

  • модуль интеграционного теста, запускающий причал (и определяющий тесты, которые запускаются для производственной .war), должен либо называться web-test-driver-for-code-extension, либо вы должны изменить операторы в блоке конфигурации runCobertura.

  • ваши отчеты о покрытии будут отображаться везде, где вы установите переменную

  • вы ДОЛЖНЫ включить "clean" в командную строку при запуске сборки для покрытия кода. 'clean' уничтожит предыдущие файлы cobertura.ser, которые, если их оставить скрываться, могут вызвать создание очень запутанных отчетов (признак того, что вам нужно `` очистить '', это то, что отчеты показывают 100% покрытие для всего, включая то, что вы знаете, никогда не звонил.

      mvn -PrunCobertura clean install      # gives you the aggregate reports.
    
  • модуль web-test-driver-for-code-extension определяет прослушиватель контекста сервлета, который явно сбрасывает метрики cobertura на диск при завершении работы веб-сервера. Предполагается, что контейнер должен делать это автоматически, но у меня это не сработало, поэтому мне пришлось подключиться к явному вызову, чтобы очистить метрики.

  • интеграционные тесты выполняются в Groovy, потому что я основал их на некоторых скелетах проектов maven, которые уже использовали groovy. Извините за добавленный беспорядок, но он показывает вам, как проводить тесты в Groovy (что в любом случае настоятельно рекомендуется).

  • Обратите внимание, что когда вы компилируете с профилем runCobertura, все ваши артефакты создаются с помощью инструментария cobertura, даже ваш файл .war. Вы, конечно, НИКОГДА не хотите, чтобы это попало в производство (во-первых, это будет работать очень медленно). Я еще не придумал пищевой способ заставить артефакты переименовывать себя так, чтобы «кобертность» была очевидна.

    <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>
    
person Chris Bedford    schedule 27.08.2012

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

Проверьте здесь: thomassundberg wordpress < / а>

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

mvn clean compile
ant instrument
mvn test
ant report

Интеграция этих шагов в sonar описана Мартин Стелингом.

тестовое покрытие в нескольких модули-проекты

person avandeursen    schedule 08.12.2012

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

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

С Уважением.

person Martín Schonaker    schedule 05.07.2011