30

我有一个包含 4 个模块的 Maven 项目 - 其中 3 个包含代码和一些测试(测试类的等于和哈希码),而第 4 个模块用于测试其他 3 个模块。

现在我想运行 cobertura 代码覆盖率工具来大致了解哪些类经过了很好的测试,哪些没有。我对该主题进行了一些调查,如果某些经过测试的源位于其他模块中,cobertura 似乎不知道生成正确的代码覆盖率和行覆盖率。

我已经阅读了一些链接,例如SeamT​​estCoverageWithCoberturaUsing the plugin Coverage within a multi-module Maven 2,但必须有一个开箱即用的解决方案。有人可以报告有关此主题的一些新方向吗?或者有没有像 cobertura 这样的 bether 工具?我偶然发现了艾玛,但这个工具不提供线路覆盖......

4

7 回答 7

19

从 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>
于 2013-08-16T21:47:29.907 回答
9

我们这里没有声纳,现在,我们无法安装它。所以我必须找到一种解决方法并得到一个。此解决方案适用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),它会很快,所以没关系。

于 2012-04-04T14:02:06.693 回答
8

根据MCOBERTURA-65,maven cobertura 插件仍然不知道如何将子模块的报告聚合成一个合并的报告。已经完成了一些工作以merge在 maven cobertura 插件上实现目标(请参阅MCOBERTURA-33),但此代码尚未包含在插件中。我自己没有测试补丁,也不能说它是否值得一试。

结果,确实有很多人建议使用 maven仪表板插件,但我个人会远离它,因为从长远来看它并不是很令人满意,而且我遇到了很多问题(技术问题,失去历史,...)。相反,我强烈推荐Sonar。查看Nemo,这是 Sonar 最新版本的公共实例,以获取此工具的现场演示。例如,参见Commons Digester项目和代码覆盖率的深入研究

于 2009-09-14T11:22:04.887 回答
3

有一些插件可以汇总 Cobertura(和其他)报告。查看声纳XRadar插件。还有仪表板插件,但有点笨拙。

FWIW Emma 确实进行了线路覆盖

于 2009-09-14T10:28:47.183 回答
2

我非常感谢 Sven Oppermann 提交他的 runCobertura 配置文件解决方案。这帮助我解决了“当您可能无法使用 Sonar 时如何获得多模块项目的聚合覆盖率报告”的问题。

我创建了一个示例,该示例演示了如何创建生成代码覆盖率报告的多模块项目,该报告不仅评估单元测试覆盖率(在所有子模块中),还评估集成测试的覆盖率,这些测试将您的应用程序作为 JETTY 中的 .WAR。该示例托管在这里:

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

如果您复制下面列出的 runCobertura 配置文件(基于 Sven 提供的配置文件),我提供的配方非常可重复使用。

以下是一些有助于您使用此配置文件的说明:

  • 启动 jetty(并定义针对生产 .war 运行的测试)的集成测试模块必须命名为 web-test-driver-for-code-coverage,或者您必须修改 runCobertura 配置块中的语句。

  • 您的覆盖率报告将出现在您设置变量的任何位置

  • 当您运行构建以进行代码覆盖时,您必须在命令行中包含“clean”。'clean' 会清除之前的 cobertura.ser 文件,如果留下这些文件可能会导致生成非常混乱的报告(您需要 'clean' 的标志是报告显示 100% 覆盖所有内容,包括您知道的内容)从来没有打电话。

      mvn -PrunCobertura clean install      # gives you the aggregate reports.
    
  • 模块 web-test-driver-for-code-coverage 定义了一个 servlet 上下文监听器,当 Web 服务器关闭时,它显式地将 cobertura 指标刷新到磁盘。假设容器应该自动执行此操作,但这对我不起作用,因此我不得不挂钩显式调用以清除指标。

  • 集成测试是在 groovy 中完成的,因为我基于一些已经使用 groovy 的 maven 项目骨架。很抱歉增加了混乱,但它确实向您展示了如何在 groovy 中进行测试(无论如何强烈推荐。)

  • 请注意,当您使用 runCobertura 配置文件进行编译时,您的所有工件都是使用 cobertura 工具创建的,甚至是您的 .war 文件。当然,你永远不想让它在生产中出现(一方面它会运行得非常慢。)我还没有想出一种食物方法来让工件重命名,这样“cobertura-ness”就很明显了。

    <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>
    
于 2012-08-27T09:57:30.593 回答
1

Thomas Sundberg 提供了一个有趣的解决方案,其中检测和测试报告是ant通过mvn.

在这里检查:thomassundberg wordpress

这意味着您必须按此顺序在父级别执行以下命令:

mvn clean compile
ant instrument
mvn test
ant report

sonarMartijn Stelinga 描述了将这些步骤集成到其中。

多模块项目中的测试覆盖率

于 2012-12-08T12:16:15.740 回答
0

由于这个答案,我可以实现与您需要的非常相似的东西:Maven - add dependency on artifact source

我刚刚添加<classifier>sources</classifier>,cobertura 也包含依赖项中的类。

问候。

于 2011-07-05T22:35:14.297 回答