如何配置多模块Maven + Sonar + JaCoCo以提供合并的覆盖率报告?


128

我已经在互联网上上下搜索了这个。有很多半的答案在那里,做Maven的属性,如${sonar.jacoco.reportPath},或org.jacoco:jacoco-maven-plugin:prepare-agent或设置maven-surefire-plugin argLine-javaagent

这些答案,无论是单独还是组合使用,都不怎么产生我的期望:覆盖率报告,如果在更高级别的测试中使用了某个类(例如正在使用的实体),则该类将覆盖该类由DAO负责,即使它自己的模块中的测试并未完全涵盖它。

请问某处是否有明确的配置以实现这一目标?

Answers:


164

我和您处在同一情况下,散布在整个Internet上的一半答案很烦人,因为似乎很多人都遇到了同样的问题,但是没有人会费心去解释他们是如何解决的。

声纳的文档是指 一个GitHub的项目,例子是有帮助的。我要解决的问题是将集成测试逻辑应用于常规单元测试(尽管正确的单元测试应特定于子模块,但并非总是如此)。

在父pom.xml中,添加以下属性:

<properties>
    <!-- Sonar -->
    <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
    <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
    <sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
    <sonar.language>java</sonar.language>
</properties>

这将使Sonar拾取同一位置(父项目中的目标文件夹)中所有子模块的单元测试报告。它还告诉Sonar重用手动运行的报告,而不是滚动自己运行的报告。我们只需将jacoco-maven-plugin放置在build / plugins内的父pom中,即可为所有子模块运行:

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.6.0.201210061924</version>
    <configuration>
        <destFile>${sonar.jacoco.reportPath}</destFile>
        <append>true</append>
    </configuration>
    <executions>
        <execution>
            <id>agent</id>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
    </executions>
</plugin>

destFile将报告文件放置在Sonar会查找的位置,并将append其添加到文件中,而不是覆盖它。这将合并同一文件中所有子模块的所有JaCoCo报告。

Sonar将针对每个子模块查看该文件,因为这就是我们在上面指出的内容,因此我们可以为Sonar中的多模块文件提供组合的单元测试结果。


奇妙!这行得通。最后!我认为我所缺少的神奇的重要咒语是<append> true </ append>
Stewart

有用!mvn package在运行之前,我必须做一个新操作才能mvn sonar:sonar生成新的报告路径。
thomasa88

2
根据示例,应使用“ sonar.jacoco.itReportPath”属性将合并结果获取到“总体代码覆盖率”中。请更新答案。
伊夫·马丁

4
“ sonar.dynamicAnalysis”也已弃用:docs.sonarqube.org/display/SONAR/Release+4.3+Upgrade+Notes
Yves Martin


23

常问问题

从那时起,我就一直想着让雅各布疯了。

我的应用程序服务器(jBoss,Glassfish。Jenkins和Sonar也位于不同的服务器上。

是。您必须使用以mode方式运行的jacoco代理,即output=tcpserverjacoco ant lib。基本上两个jar秒。这将给您99%的成功。

jacoco代理如何工作?

您附加一个字符串

-javaagent:[your_path]/jacocoagent.jar=destfile=/jacoco.exec,output=tcpserver,address=*

到您的应用程序服务器JAVA_OPTS并重新启动它。在此字符串中,仅需[your_path]替换为jacocoagent.jar的路径,该路径已存储(存储!)在运行应用服务器的VM上。从那时起,您启动应用程序服务器,将对部署的所有应用程序进行动态监视,并且它们的活动(即代码使用情况)将随时可以通过tcl请求以jacocos .exec格式提供。

我可以重置jacoco代理以仅从测试开始就开始收集执行数据吗?

是的,为此,您需要位于jenkins工作区中的jacocoant.jar和ant构建脚本。

因此,基本上,我从http://www.eclemma.org/jacoco/中需要的是位于我的jenkins工作区中的jacocoant.jar和位于我的应用程序服务器VM上的jacocoagent.jar?

那就对了。

我不想使用ant,听说jacoco maven插件也可以做所有事情。

这是不对的,jacoco maven插件可以收集单元测试数据和一些集成测试数据(请参阅Arquillian Jacoco),但是例如,如果您有放心的测试作为jenkins中的单独构建,并且想要显示多模块覆盖率,我可以没有看到maven插件可以为您提供帮助。

雅各博代理商到底生产什么?

仅覆盖数据.exec格式。声纳然后可以阅读它。

jacoco是否需要知道我的Java类位于哪里?

不,声纳有,但雅各科没有。当您mvn sonar:sonar上课时,路径就起作用了。

那蚂蚁脚本呢?

它必须显示在您的詹金斯工作区中。我的蚂蚁脚本jacoco.xml看起来像这样:

<project name="Jacoco library to collect code coverage remotely" xmlns:jacoco="antlib:org.jacoco.ant">
    <property name="jacoco.port" value="6300"/>
    <property name="jacocoReportFile" location="${workspace}/it-jacoco.exec"/>

    <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
        <classpath path="${workspace}/tools/jacoco/jacocoant.jar"/>
    </taskdef>

    <target name="jacocoReport">
            <jacoco:dump address="${jacoco.host}" port="${jacoco.port}" dump="true" reset="true" destfile="${jacocoReportFile}" append="false"/>
    </target>

    <target name="jacocoReset">
            <jacoco:dump address="${jacoco.host}" port="${jacoco.port}" reset="true" destfile="${jacocoReportFile}" append="false"/>
        <delete file="${jacocoReportFile}"/>
    </target>
</project>

调用此脚本时应传递的两个强制性参数 -Dworkspace=$WORKSPACE 使用它来指向您的jenkins工作区和-Djacoco.host=yourappserver.com主机,而无需http://

另请注意,我将我放置jacocoant.jar在$ {workspace} /tools/jacoco/jacocoant.jar中

接下来我该怎么办?

您是否使用jacocoagent.jar启动了应用服务器?

您是否将ant脚本和jacocoant.jar放入jenkins工作区中?

如果是,那么最后一步是配置jenkins构建。这是策略:

  1. 调用ant target jacocoReset以重置所有先前收集的数据。
  2. 运行测试
  3. 调用蚂蚁目标jacocoReport以获取报告

如果一切正常,您将it-jacoco.exec在构建工作区中看到。

看截图,我也已经ant在我的工作区的$WORKSPACE/tools/antdir中安装了,但是您可以使用在詹金斯中安装的一个。

在此处输入图片说明

如何在声纳中推送此报告?

Maven sonar:sonar将完成此工作(不要忘记对其进行配置),将其指向main pom.xml,这样它将在所有模块中运行。使用sonar.jacoco.itReportPath=$WORKSPACE/it-jacoco.exec参数告诉声纳您的集成测试报告位于何处。每当它分析新的模块类时,它将在中查找有关coverage的信息it-jacoco.exec

我的`target`目录中已经有jacoco.exec,`mvn sonar:sonar`会忽略/删除它

默认情况下mvn sonar:sonarclean删除目标目录,请使用sonar.dynamicAnalysis=reuseReports它来避免它。


20

自0.7.7版以来的新方法

从0.7.7版开始,有一种创建汇总报告的新方法:

您创建一个单独的“报告”项目,该项目将收集所有必要的报告(聚合器项目中的任何目标均在其模块之前执行因此无法使用)。

aggregator pom
  |- parent pom
  |- module a
  |- module b
  |- report module 

根POM看起来像这样(不要忘了在模块添加新的报表模块):

<build>
<plugins>
  <plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.7.8</version>
    <executions>
      <execution>
        <id>prepare-agent</id>
        <goals>
          <goal>prepare-agent</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
</plugins>

每个子模块的poms根本不需要更改。报表模块中的pom 如下所示:

<!-- Add all sub modules as dependencies here -->
<dependencies>
  <dependency>
    <module a>
  </dependency>
  <dependency>
    <module b>
  </dependency>
 ...

  <build>
    <plugins>
      <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.7.8</version>
        <executions>
          <execution>
            <id>report-aggregate</id>
            <phase>verify</phase>
            <goals>
              <goal>report-aggregate</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

一个完整的例子可以在这里找到。


3
这可行。汇总报告显示了所有模块的累积代码覆盖率。您是否曾经尝试在Sonar中查看此累积报告?我使用sonar-qube读取了各个报告的jacoco.exec,但是由于此报告已聚合,因此在报告模块中看不到聚合的jacoco.exec。
Swetha V

@SwethaV是否成功?我们处于同一位置,需要找到一种方法来生成聚集的exec :)
Vinky

我们使用声纳qube版本6.X,它具有自己的测试覆盖页面,因此我在那里不需要jacoco。对于较旧的版本,我们安装了cobertura插件,该插件也提供了此功能...
Lonzak

11

我将发布我的解决方案,因为它与其他解决方案略有不同,并且在现有答案的帮助下,我花了整整一天的时间才做对。

对于多模块Maven项目:

ROOT
|--WAR
|--LIB-1
|--LIB-2
|--TEST

WAR项目是主​​要的Web应用程序,而LIB1和2是WAR依赖的其他模块,并且TEST是集成测试的所在地。 TEST启动一个嵌入式Tomcat实例(而不是通过Tomcat插件),并运行WAR项目并通过一组JUnit测试对其进行测试。在WARLIB项目都有自己的单元测试。

所有这些的结果是,在SonarQube中,集成和单元测试的覆盖范围是分离的并且可以区分。

ROOT pom.xml

<!-- Sonar properties-->
<sonar.jacoco.itReportPath>${project.basedir}/../target/jacoco-it.exec</sonar.jacoco.itReportPath>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.language>java</sonar.language>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>

<!-- build/plugins (not build/pluginManagement/plugins!) -->
<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.7.6.201602180812</version>
    <executions>
        <execution>
            <id>agent-for-ut</id>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
            <configuration>
                <append>true</append>
                <destFile>${sonar.jacoco.reportPath}</destFile>
            </configuration>
        </execution>
        <execution>
            <id>agent-for-it</id>
            <goals>
                <goal>prepare-agent-integration</goal>
            </goals>
            <configuration>
                <append>true</append>
                <destFile>${sonar.jacoco.itReportPath}</destFile>
            </configuration>
        </execution>
    </executions>
</plugin>

WARLIB 并且TEST pom.xml将继承的JaCoCo插件执行。

TEST pom.xml

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.19.1</version>
    <executions>
        <execution>
            <goals>
                <goal>integration-test</goal>
                <goal>verify</goal>
            </goals>
            <configuration>
                <skipTests>${skip.tests}</skipTests>
                <argLine>${argLine} -Duser.timezone=UTC -Xms256m -Xmx256m</argLine>
                <includes>
                    <includes>**/*Test*</includes>
                </includes>
            </configuration>
        </execution>
    </executions>
</plugin>

我还发现Petri Kainulainens博客文章“使用JaCoCo Maven插件为单元和集成测试创建代码覆盖率报告”对于JaCoCo设置方面很有价值。


我需要在某个阶段更新此帖子,因为它实际上是次优的。agent-for-it仅在TEST模块中运行测试时才需要此选项,但是当前配置使它在没有值的其他所有模块上运行。改进之处在于可以agent-for-ut在所有其他模块中agent-for-it运行,而只能在中运行TEST
markdsievers

6

我在父级pom中使用的配置,其中我具有单独的单元和集成测试阶段。

我在父POM属性中配置以下属性

    <maven.surefire.report.plugin>2.19.1</maven.surefire.report.plugin>
    <jacoco.plugin.version>0.7.6.201602180812</jacoco.plugin.version>
    <jacoco.check.lineRatio>0.52</jacoco.check.lineRatio>
    <jacoco.check.branchRatio>0.40</jacoco.check.branchRatio>
    <jacoco.check.complexityMax>15</jacoco.check.complexityMax>
    <jacoco.skip>false</jacoco.skip>
    <jacoco.excludePattern/>
    <jacoco.destfile>${project.basedir}/../target/coverage-reports/jacoco.exec</jacoco.destfile>

    <sonar.language>java</sonar.language>
    <sonar.exclusions>**/generated-sources/**/*</sonar.exclusions>
    <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
    <sonar.coverage.exclusions>${jacoco.excludePattern}</sonar.coverage.exclusions>
    <sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
    <sonar.jacoco.reportPath>${project.basedir}/../target/coverage-reports</sonar.jacoco.reportPath>

    <skip.surefire.tests>${skipTests}</skip.surefire.tests>
    <skip.failsafe.tests>${skipTests}</skip.failsafe.tests>

我将插件定义置于插件管理下。

请注意,我为surefire(surefireArgLine)和failsafe(failsafeArgLine)参数定义了一个属性,以允许jacoco将javaagent配置为与每个测试一起运行。

在pluginManagement下

  <build>
     <pluginManagment>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <fork>true</fork>
                    <meminitial>1024m</meminitial>
                    <maxmem>1024m</maxmem>
                    <compilerArgument>-g</compilerArgument>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                    <encoding>${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.19.1</version>
                <configuration>
                    <forkCount>4</forkCount>
                    <reuseForks>false</reuseForks>
                    <argLine>-Xmx2048m ${surefireArgLine}</argLine>
                    <includes>
                        <include>**/*Test.java</include>
                    </includes>
                    <excludes>
                        <exclude>**/*IT.java</exclude>
                    </excludes>
                    <skip>${skip.surefire.tests}</skip>
                </configuration>
            </plugin>
            <plugin>
                <!-- For integration test separation -->
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>2.19.1</version>
                <dependencies>
                    <dependency>
                        <groupId>org.apache.maven.surefire</groupId>
                        <artifactId>surefire-junit47</artifactId>
                        <version>2.19.1</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <forkCount>4</forkCount>
                    <reuseForks>false</reuseForks>
                    <argLine>${failsafeArgLine}</argLine>
                    <includes>
                        <include>**/*IT.java</include>
                    </includes>
                    <skip>${skip.failsafe.tests}</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>integration-test</id>
                        <goals>
                            <goal>integration-test</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>verify</id>
                        <goals>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <!-- Code Coverage -->
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco.plugin.version}</version>
                <configuration>
                    <haltOnFailure>true</haltOnFailure>
                    <excludes>
                        <exclude>**/*.mar</exclude>
                        <exclude>${jacoco.excludePattern}</exclude>
                    </excludes>
                    <rules>
                        <rule>
                            <element>BUNDLE</element>
                            <limits>
                                <limit>
                                    <counter>LINE</counter>
                                    <value>COVEREDRATIO</value>
                                    <minimum>${jacoco.check.lineRatio}</minimum>
                                </limit>
                                <limit>
                                    <counter>BRANCH</counter>
                                    <value>COVEREDRATIO</value>
                                    <minimum>${jacoco.check.branchRatio}</minimum>
                                </limit>
                            </limits>
                        </rule>
                        <rule>
                            <element>METHOD</element>
                            <limits>
                                <limit>
                                    <counter>COMPLEXITY</counter>
                                    <value>TOTALCOUNT</value>
                                    <maximum>${jacoco.check.complexityMax}</maximum>
                                </limit>
                            </limits>
                        </rule>
                    </rules>
                </configuration>
                <executions>
                    <execution>
                        <id>pre-unit-test</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <destFile>${jacoco.destfile}</destFile>
                            <append>true</append>
                            <propertyName>surefireArgLine</propertyName>
                        </configuration>
                    </execution>
                    <execution>
                        <id>post-unit-test</id>
                        <phase>test</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                        <configuration>
                            <dataFile>${jacoco.destfile}</dataFile>
                            <outputDirectory>${sonar.jacoco.reportPath}</outputDirectory>
                            <skip>${skip.surefire.tests}</skip>
                        </configuration>
                    </execution>
                    <execution>
                        <id>pre-integration-test</id>
                        <phase>pre-integration-test</phase>
                        <goals>
                            <goal>prepare-agent-integration</goal>
                        </goals>
                        <configuration>
                            <destFile>${jacoco.destfile}</destFile>
                            <append>true</append>
                            <propertyName>failsafeArgLine</propertyName>
                        </configuration>
                    </execution>
                    <execution>
                        <id>post-integration-test</id>
                        <phase>post-integration-test</phase>
                        <goals>
                            <goal>report-integration</goal>
                        </goals>
                        <configuration>
                            <dataFile>${jacoco.destfile}</dataFile>
                            <outputDirectory>${sonar.jacoco.reportPath}</outputDirectory>
                            <skip>${skip.failsafe.tests}</skip>
                        </configuration>
                    </execution>
                    <!-- Disabled until such time as code quality stops this tripping
                    <execution>
                        <id>default-check</id>
                        <goals>
                            <goal>check</goal>
                        </goals>
                        <configuration>
                            <dataFile>${jacoco.destfile}</dataFile>
                        </configuration>
                    </execution>
                    -->
                </executions>
            </plugin>
            ...

在构建部分

 <build>
     <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
        </plugin>

        <plugin>
            <!-- for unit test execution -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
        </plugin>
        <plugin>
            <!-- For integration test separation -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
        </plugin>
        <plugin>
            <!-- For code coverage -->
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
        </plugin>
        ....

在报告部分

    <reporting>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-report-plugin</artifactId>
            <version>${maven.surefire.report.plugin}</version>
            <configuration>
                <showSuccess>false</showSuccess>
                <alwaysGenerateFailsafeReport>true</alwaysGenerateFailsafeReport>
                <alwaysGenerateSurefireReport>true</alwaysGenerateSurefireReport>
                <aggregate>true</aggregate>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>${jacoco.plugin.version}</version>
            <configuration>
                <excludes>
                    <exclude>**/*.mar</exclude>
                    <exclude>${jacoco.excludePattern}</exclude>
                </excludes>
            </configuration>
        </plugin>
     </plugins>
  </reporting>

1
我看到您在<append>true</append>以下各prepare-agent节中都有配置...
Stewart

重点。阅读我对其他答案的评论。这是我缺少的重要成分,其他文档中找不到。
斯图尔特

你有一个github链接吗?我想做完全类似的配置
Rohit Kasat

@Rhit-不,我不知道,至少不在公共存储库中。
sweetfa

这在Sonar Qube 6.5版(内部版本27846)中非常有效...:D代码覆盖率将正确显示。
udoline

6

有一种方法可以完成此任务。魔术是创建一个组合的jacoco.exec文件。而使用Maven 3.3.1,有一种简单的方法来实现这一点。这是我的个人资料:

<profile>
    <id>runSonar</id>
    <activation>
        <property>
            <name>runSonar</name>
            <value>true</value>
        </property>
    </activation>
    <properties>
        <sonar.language>java</sonar.language>
        <sonar.host.url>http://sonar.url</sonar.host.url>
        <sonar.login>tokenX</sonar.login>
        <sonar.jacoco.reportMissing.force.zero>true</sonar.jacoco.reportMissing.force.zero>
        <sonar.jacoco.reportPath>${jacoco.destFile}</sonar.jacoco.reportPath>
        <jacoco.destFile>${maven.multiModuleProjectDirectory}/target/jacoco_analysis/jacoco.exec</jacoco.destFile>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>default-prepare-agent</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <append>true</append>
                            <destFile>${jacoco.destFile}</destFile>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.sonarsource.scanner.maven</groupId>
                    <artifactId>sonar-maven-plugin</artifactId>
                    <version>3.2</version>
                </plugin>
                <plugin>
                    <groupId>org.jacoco</groupId>
                    <artifactId>jacoco-maven-plugin</artifactId>
                    <version>0.7.8</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</profile>

如果将此配置文件添加到父pom并致电,mvn clean install sonar:sonar -DrunSonar您将获得完整的报道。

这里的魔力是maven.multiModuleProjectDirectory。此文件夹始终是您开始进行Maven构建的文件夹。


经过许多其他解决方案后,这对我有用。
Jimson Kannanthara James

唯一的问题是,mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.4.0.905:sonar -DrunSonar由于A required class was missing while executing org.sonarsource.scanner.maven:sonar-maven-plugin:3.0.1:sonar: org/sonar/batch/bootstrapper/IssueListener错误,我不得不使用命令运行声纳。
Jimson Kannanthara James

1
不要使用这种魔术。给定的属性是实现的详细信息,不得依赖。-Maven开发人员团队
Michael-O,

4

我找到了新的Sonar版本的另一种解决方案,其中不推荐使用JaCoCo的二进制报告格式(* .exec),首选格式是XML(SonarJava 5.12和更高版本)。该解决方案非常简单,并且与以前的解决方案类似,该解决方案在本主题的父目录中带有* .exec报告:https ://stackoverflow.com/a/15535970/4448263 。

假设我们的项目结构为:

moduleC - aggregate project's pom
  |- moduleA - some classes without tests
  |- moduleB - some classes depending from moduleA and tests for classes in both modules: moduleA and moduleB

您需要在聚合项目的pom中执行以下maven构建插件配置:

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.5</version>
    <executions>
        <execution>
            <id>prepare-and-report</id>
            <goals>
                <goal>prepare-agent</goal>
                <goal>report</goal>
            </goals>
        </execution>
        <execution>
            <id>report-aggregate</id>
            <phase>verify</phase>
            <goals>
                <goal>report-aggregate</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.basedir}/../target/site/jacoco-aggregate</outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>

然后使用Maven构建项目:

mvn clean verify

对于Sonar,您应该在管理GUI中设置属性:

sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml,../target/site/jacoco-aggregate/jacoco.xml

或使用命令行:

mvn sonar:sonar -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml,../target/site/jacoco-aggregate/jacoco.xml

描述

这将为默认目录下的每个模块创建二进制报告target/jacoco.exec。然后在默认目录:中为每个模块创建XML报告target/site/jacoco/jacoco.xml。然后${project.basedir}/../target/site/jacoco-aggregate/为相对于每个模块的父目录的自定义目录中的每个模块创建一个汇总报告。对于moduleA和moduleB这将是通用路径moduleC/target/site/jacoco-aggregate/

由于模块B依赖于模块A,因此模块B将最后构建,并且其报告将在Sonar中用作模块A和B的总覆盖率报告。

除了汇总报告之外,我们还需要一个常规的模块报告,因为JaCoCo汇总报告仅包含相关性的coverage数据。

这两种类型的报告一起提供了Sonar的完整覆盖范围数据。

有一个小限制:您应该能够在项目的父目录中写一个报告(应该有权限)。或者,您可以jacoco.skip=true在根项目的pom.xml(moduleC)以及jacoco.skip=false具有类和测试的模块(moduleA和moduleB)中设置属性。


2
    <sonar.language>java</sonar.language>
    <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
    <sonar.jacoco.reportPath>${user.dir}/target/jacoco.exec</sonar.jacoco.reportPath>
    <sonar.jacoco.itReportPath>${user.dir}/target/jacoco-it.exec</sonar.jacoco.itReportPath>
    <sonar.exclusions>
        file:**/target/generated-sources/**,
        file:**/target/generated-test-sources/**,
        file:**/target/test-classes/**,
        file:**/model/*.java,
        file:**/*Config.java,
        file:**/*App.java
    </sonar.exclusions>

            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.7.9</version>
                <executions>
                    <execution>
                        <id>default-prepare-agent</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                        <configuration>
                            <destFile>${sonar.jacoco.reportPath}</destFile>
                            <append>true</append>
                            <propertyName>surefire.argLine</propertyName>
                        </configuration>
                    </execution>
                    <execution>
                        <id>default-prepare-agent-integration</id>
                        <goals>
                            <goal>prepare-agent-integration</goal>
                        </goals>
                        <configuration>
                            <destFile>${sonar.jacoco.itReportPath}</destFile>
                            <append>true</append>
                            <propertyName>failsafe.argLine</propertyName>
                        </configuration>
                    </execution>
                    <execution>
                        <id>default-report</id>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>default-report-integration</id>
                        <goals>
                            <goal>report-integration</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>             

2

作为Sonars sonar.jacoco.reportPathsonar.jacoco.itReportPath并且sonar.jacoco.reportPaths已经弃用了,您sonar.coverage.jacoco.xmlReportPaths现在应该使用。如果要使用Sonar和Jacoco配置多​​模块Maven项目,这也会产生一些影响。

正如@Lonzak 指出的那样,自从Sonar 0.7.7开始,您就可以使用Sonars报告聚集目标。只需将以下依赖项放入您的父pom中:

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.5</version>
    <executions>
        <execution>
            <id>report</id>
            <goals>
                <goal>report-aggregate</goal>
            </goals>
            <phase>verify</phase>
        </execution>
    </executions>
</plugin>

由于jacoco-maven-plugin的当前版本与xml-reports兼容,因此将为它自己的目标文件夹中的每个模块创建一个包含文件的site / jacoco-aggregate文件夹jacoco.xml

要使Sonar合并所有模块,请使用以下命令:

mvn -Dsonar.coverage.jacoco.xmlReportPaths=full-path-to-module1/target/site/jacoco-aggregate/jacoco.xml,module2...,module3... clean verify sonar:sonar

为了使我的回答简短而准确,我没有提及maven-surefire-plugin maven-failsafe-plugin依赖项。您可以添加它们而无需任何其他配置:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-failsafe-plugin</artifactId>
    <version>2.22.2</version>
    <executions>
        <execution>
        <id>integration-test</id>
            <goals>
                <goal>integration-test</goal>
            </goals>
        </execution>
    </executions>
</plugin>

1

您可以在maven上调用一个称为merge的ant任务,以将所有coverage文件(* .exec)放到同一文件中。

如果要运行单元测试,请使用阶段prepare-package;如果要运行集成测试,请使用post-integration-test

这个站点有一个如何在Maven项目中调用jacoco ant任务的示例

您可以在声纳上使用此合并文件。


0

要进行单元测试和集成测试,可以使用带有受限包含/排除项的maven-surefire-plugin和maven-failsafe-plugin。我在与声纳/雅各布联系时正在玩CDI,所以我最终完成了这个项目:

https://github.com/FibreFoX/cdi-sessionscoped-login/

也许对您有一点帮助。在我的pom.xml中,我通过在指定的测试插件的configuration-section中设置argLine-option来隐式使用“ -javaagent”。我不会尝试在MAVEN项目中显式使用ANT,因为对我来说,它在两个世界之间存在很多混合。

我只有一个单模块maven项目,但也许它可以帮助您调整自己的工作范围。

注意:也许不是所有的Maven插件都在up2date中,也许某些问题在更高版本中已得到解决


谢谢你 我看一下,让您知道它是如何工作的。可能不是这个星期:)
斯图尔特

0

这个示例对我来说非常有效:

<plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.8.2</version>
            <executions>
                <execution>
                    <id>pre-unit-test</id>
                    <goals>
                        <goal>prepare-agent</goal>
                    </goals>
                    <configuration>
                        <destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile>
                        <propertyName>surefireArgLine</propertyName>
                    </configuration>
                </execution>
                <execution>
                    <id>pre-integration-test</id>
                    <goals>
                        <goal>prepare-agent-integration</goal>
                    </goals>
                    <configuration>
                        <destFile>${project.build.directory}/coverage-reports/jacoco-it.exec</destFile>
                        <!--<excludes>
                            <exclude>com.asimio.demo.rest</exclude>
                            <exclude>com.asimio.demo.service</exclude>
                        </excludes>-->
                        <propertyName>testArgLine</propertyName>
                    </configuration>
                </execution>
                <execution>
                    <id>post-integration-test</id>
                    <phase>post-integration-test</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                    <configuration>
                        <dataFile>${project.build.directory}/coverage-reports/jacoco-it.exec</dataFile>
                        <outputDirectory>${project.reporting.outputDirectory}/jacoco-it</outputDirectory>
                    </configuration>
                </execution>
                <execution>
                    <id>post-unit-test</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                    <configuration>
                        <dataFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</dataFile>
                        <outputDirectory>${project.reporting.outputDirectory}/jacoco-ut</outputDirectory>
                    </configuration>
                </execution>
                <execution>
                    <id>merge-results</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>merge</goal>
                    </goals>
                    <configuration>
                        <fileSets>
                            <fileSet>
                                <directory>${project.build.directory}/coverage-reports</directory>
                                <includes>
                                    <include>*.exec</include>
                                </includes>
                            </fileSet>
                        </fileSets>
                        <destFile>${project.build.directory}/coverage-reports/aggregate.exec</destFile>
                    </configuration>
                </execution>
                <execution>
                    <id>post-merge-report</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                    <configuration>
                        <dataFile>${project.build.directory}/coverage-reports/aggregate.exec</dataFile>
                        <outputDirectory>${project.reporting.outputDirectory}/jacoco-aggregate</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.18.1</version>
            <configuration>
                <argLine>${surefireArgLine}</argLine>
                <!--<skipTests>${skip.unit.tests}</skipTests>-->
                <includes>
                    <include>**/*Test.java</include>
                    <!--<include>**/*MT.java</include>
                    <include>**/*Test.java</include>-->
                </includes>
            <!--    <skipTests>${skipUTMTs}</skipTests>-->
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.12.4</version>
            <configuration>
                <!--<skipTests>${skipTests}</skipTests>
                <skipITs>${skipITs}</skipITs>-->
                <argLine>${testArgLine}</argLine>
                <includes>
                    <include>**/*IT.java</include>
                </includes>
                <!--<excludes>
                    <exclude>**/*UT*.java</exclude>
                </excludes>-->
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>integration-test</goal>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

请为您的答案提供一些解释
-mishsx

@mishsx很好的解释文章:natritmeyer.com/howto/…–
SerhatTopkaya
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.