cobertura on maven многомодульный проект
У меня есть проект Maven с 4 модулями - 3 из них содержат код и некоторые тесты (тестирование на равенство и хэш-код классов), тогда как 4-й модуль предназначен для тестирования 3 других модулей.
Теперь я хочу запустить инструмент покрытия кода cobertura, чтобы получить представление о том, какие классы хорошо протестированы, а какие нет. Я провел несколько исследований на эту тему, и кажется, что cobertura не знает о том, как генерировать правильные проценты покрытия кода и линейные покрытия, если некоторые проверяемые источники находятся в других модулях.
Я прочитал некоторые ссылки, такие как http://seamframework.org/Documentation/SeamTestCoverageWithCobertura и Использование плагина Coverage в многомодульном Maven 2, но должно быть готовое решение. Кто-нибудь может сообщить некоторые новые направления на эту тему? Или есть другие инструменты, такие как cobertura? Я наткнулся на Эмму, но этот инструмент не предлагает покрытие линии...
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>
У нас нет сонара здесь и сейчас, мы не можем его установить. Поэтому я должен был найти обходной путь и получил его. Это решение работает с простым 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
Формат (для Дженкинса) быстрый, поэтому не имеет значения.
Согласно MCOBERTURA-65, плагин maven cobertura до сих пор не знает, как объединять отчеты подмодулей в консолидированный. Некоторая работа была проделана для реализации merge
цель для плагина maven cobertura (см. MCOBERTURA-33), но этот код еще не был включен в плагин. Я не тестировал патч сам и не могу сказать, стоит ли попробовать.
В результате многие люди действительно предлагают использовать плагин панели инструментов maven, но я лично буду держаться подальше от него, так как он не очень приятен в долгосрочной перспективе, и я столкнулся с множеством проблем (технические проблемы, потеря истории).,...). Вместо этого я настоятельно рекомендую сонар. Посмотрите на Nemo, публичный экземпляр последней версии Sonar, для демонстрации этого инструмента в реальном времени. См., Например, проект Commons Digester и детализацию покрытия кода.
Есть несколько плагинов, которые объединяют отчеты Cobertura (и других). Проверьте плагин сонара и XRadar. Существует также плагин панели инструментов, но он немного неуклюжий.
FWIW Эмма делает покрытие линии.
Я действительно хотел бы поблагодарить Свена Опперманна за представление его решения для профиля runCobertura. Это помогло мне решить вопрос: "Как вы получаете сводные отчеты о покрытии для многомодульных проектов, когда вы не можете использовать Sonar?
Я создал пример, который демонстрирует, как создавать многомодульные проекты, которые генерируют отчеты о покрытии кода, которые оценивают не только покрытие модульных тестов (во всех подмодулях), но также и освещение ИНТЕГРАЦИОННЫХ ИСПЫТАНИЙ, КОТОРЫЕ ПОДКЛЮЧАЮТ ВАШЕ ПРИЛОЖЕНИЕ КАК. Пример размещен здесь:
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>
Томас Сундберг предлагает интересное решение, в котором отчеты по измерительным приборам и испытаниям выполняются ant
, но все тестирование и управление зависимостями через mvn
,
Проверьте здесь: Томассундберг WordPress
Это означает, что вы должны выполнить команды ниже на родительском уровне в следующем порядке:
mvn clean compile
ant instrument
mvn test
ant report
Интеграция этих шагов в sonar
описан Мартейн Стелинга.
Благодаря этому ответу я могу реализовать нечто похожее на то, что вам нужно: Maven - добавить зависимость от источника артефакта.
Я только добавил <classifier>sources</classifier>
и cobertura также включает в себя классы из зависимостей.
С уважением.