Cobertura в многомодульном проекте Maven
Вопрос
У меня есть проект Maven с 4 модулями - 3 из них содержат код и некоторые тесты (тестирование равных и хэш-код классов), тогда как 4-й модуль предназначен для тестирования трех других модулей.
Теперь я хочу запустить инструмент покрытия кода cobertura, чтобы получить представление о том, какие классы хорошо протестированы, а какие нет.Я провел некоторые исследования по этой теме, и похоже, что cobertura не знает, как генерировать правильные проценты покрытия кода и покрытия строк, если некоторые тестируемые источники расположены внутри других модулей.
Я прочитал некоторые ссылки, такие как ШовТестПокрытиеСКобертура и Использование плагина Coverage в многомодульном Maven 2 но должно быть нестандартное решение.Может ли кто-нибудь сообщить о каких-то новых направлениях по этой теме?Или есть другие инструменты, такие как кобертура?Я наткнулся на Эмму, но этот инструмент не обеспечивает покрытие линии...
Решение
Начиная с версии 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.Это помогло Как получить сводные отчеты о покрытии для многомодульных проектов, когда вы можете быть не готовы возможность использования гидролокатора.
Я создал пример, демонстрирующий, как создавать многомодульные проекты, которые создают отчеты о покрытии кода, оценивающие не только покрытие модульных тестов (во всех подмодулях), но и покрытие по ИНТЕГРАЦИОННЫЕ ТЕСТЫ, КОТОРЫЕ ПРИНОСЯТ ПОДНИМИТЕ ПРИЛОЖЕНИЕ В КАЧЕСТВЕ . ВОЙНА НА ПРИСТАНИ.Пример размещен здесь:
http://dl.dropbox.com/u/9940067/code/multi-module-cobertura.zip
Рецепт, который я предоставляю, можно использовать повторно, если вы скопируете профиль runCobertura, указанный ниже (на основе одного предоставлено Свеном.)
Вот несколько примечаний, которые помогут вам использовать этот профиль:
Модуль интеграционного тестирования, который запускает привод (и определяет тесты, которые работают против производственного .WAR), должен быть либо назван веб-тестом-драйвером для кода, либо необходимо изменить операции в блоке конфигурации RunCobertura.
ваши отчеты о покрытии будут появляться везде, где вы установите переменную
вы ДОЛЖНЫ включить «чистый» в командную строку при запуске сборки для покрытия кода.'clean' сдует предыдущие файлы cobertura.ser, которые, если их оставить без присмотра, могут привести к очень запутанным отчетам (признаком того, что вам нужно «очистить», является то, что отчеты показывают 100% покрытие всего, включая то, что, как вы знаете, никогда не вызывается.
mvn -PrunCobertura clean install # gives you the aggregate reports.
Модуль веб-тест-драйвер для кода, определяет слушателя контекста сервлета, который явно промывает метрики 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>
Томас Сандберг предлагает интересное решение, в котором инструментарий и отчеты о тестировании выполняются через ant
, но все тестирование и управление зависимостями через mvn
.
Проверьте здесь: Томасундберг WordPress
Это означает, что вы должны выполнить команды ниже на родительском уровне в следующем порядке:
mvn clean compile
ant instrument
mvn test
ant report
Интеграция этих шагов в sonar
описана Martijn Stelinga.
Благодаря этому ответу я мог бы реализовать что-то очень похожее на то, что вам нужно: Maven – добавить зависимость от источника артефакта
я только что добавил <classifier>sources</classifier>
и cobertura также включает классы из зависимостей.
С уважением.