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

我在网上到处找这个。有许多半答案在那里,与 Maven 属性,如 ${sonar.jacoco.reportPath},或 org.jacoco:jacoco-maven-plugin:prepare-agent或设置 maven-surefire-plugin argLine-javaagent

不知怎么的,这些答案,无论是单独的还是组合的,都没有产生我想要的结果: 一个覆盖率报告,显示一个类是否被覆盖,如果它被用于堆栈更高层的测试中,例如 DAO 使用的实体,即使它没有被它自己的模块中的测试完全覆盖。

有没有一个明确的配置,实现这一点,请?

147249 次浏览

您可以在 maven 上调用一个名为 翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳的 ant 任务,将所有覆盖文件(* 。(exec)放在同一个文件中。

如果运行单元测试,请使用阶段 准备包裹,如果运行集成测试,请使用 积分后测试积分后测试

这个站点 有一个在 maven 项目中如何调用 Jacoco ant task 的例子

你可以在声纳上使用这个合并文件。

要进行单元测试和集成测试,你可以使用 maven-surefire-plugin 和 maven-faulsafe-plugin,其中包含/排除受限内容。我在与声纳/Jacoco 取得联系的同时,还在玩 CDI,所以我最终选择了这个项目:

Https://github.com/fibrefox/cdi-sessionscoped-login/

也许对你有点帮助。在 pom.xml 中,通过在指定的 test-plugins 的 configuration-section 中设置 argLine-选项,我使用了“-javaagent”。 在 MAVEN 项目中显式地使用 ANT 是我不愿意尝试的,对我来说它是两个世界的混合。

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

注意: 也许不是所有的 maven-plugins 都是 up2date,也许有些问题在以后的版本中已经解决了

我和你的情况一样,在互联网上散布的一半答案是相当恼人的,因为似乎很多人都有同样的问题,但没有人愿意费心解释他们是如何解决的。

声纳医生指的是有帮助的 一个带有示例的 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将报告文件放置在声纳将要查找的位置,append使其附加到文件而不是覆盖它。这将合并同一文件中所有子模块的所有 JaCoCo 报告。

声纳将查看每个子模块的文件,因为这就是我们在上面指出的,给我们声纳中多个模块文件的单元测试结果。

常见问题

自从那次我和 Jacoco 疯了之后,我脑子里就一直在想这些问题。

我的应用服务器(jBoss,Glassfish。.)在伊拉克,叙利亚,随便什么地方。.是否有可能在运行集成测试时获得多模块覆盖率?詹金斯和声纳也在不同的服务器上。

是的。您必须使用在模式 output=tcpserver中运行的 Jacoco 探员,Jacoco ant lib。基本上是两个 jar。这会让你99% 成功。

Jacoco 探员是怎么工作的?

附加一个字符串

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

到应用服务器 JAVA _ OPTS 并重新启动它。在这个字符串中,只有 [your_path]必须替换为保存(存储它!)的 jacocurrenent.jar 路径应用程序服务器运行的虚拟机上。自从您启动应用程序服务器以来,所有部署的应用程序都将被动态监视,并且它们的活动(即代码使用)将为您进入 Jacocos 做好准备。按 tcl 请求执行格式。

我是否可以重置 jacoco 代理,使其仅从测试开始时开始收集执行数据?

是的,为此,您需要在 Jenkins 工作区中使用 jacocoant.jar 和 ant 构建脚本。

所以基本上我需要的 http://www.eclemma.org/jacoco/就是 jenkins 工作区中的 jacocoant.jar 和应用服务器 VM 中的 jacoecent.jar?

没错。

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

这是不对的,Jacoco maven 插件可以收集单元测试数据和一些集成测试数据(参见 Arquillian Jacoco) ,但是如果你有一个例子放心测试作为一个独立的构建在 jenkins,并希望显示多模块的覆盖率,我不知道如何 maven 插件可以帮助你。

Jacoco 代理到底生产什么?

只有 .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 使用它指向没有 http://的 Jenkins 工作区和 -Djacoco.host=yourappserver.com主机

还要注意,我将 jacocoant.jar设置为 ${ workspace }/tools/jacoco/jacocoant.jar

接下来我该做什么?

你的应用程序服务器是用 Jaco .jar 启动的吗?

你有没有把 Ant script 和 jacocoant.jar 放进 Jenkins 的工作区?

如果是,最后一步是配置一个 jenkins 构建:

  1. 调用蚂蚁目标 jacocoReset来重置以前收集的所有数据。
  2. 做检查吧
  3. 调用蚂蚁目标 jacocoReport获取报告

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

看看截图,我也有 ant安装在我的工作区在 $WORKSPACE/tools/ant目录,但你可以使用一个是安装在您的 jenkins。

enter image description here

如何在声纳中推送这个报告?

Maven sonar:sonar将完成这项工作(不要忘记配置它) ,将它指向 main pom.xml,这样它将运行所有模块。使用 sonar.jacoco.itReportPath=$WORKSPACE/it-jacoco.exec参数告诉声纳集成测试报告的位置。每次它将分析新的模块类,它将寻找关于 it-jacoco.exec覆盖率的信息。

我的“ target”dir 中已经有 jacoco.exec,“ mvn 声纳: sonar”忽略/删除它

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

我在父级 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)和 faulsafeArgLine 参数定义了一个属性,以允许 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>

我将张贴我的解决方案,因为它微妙地不同于其他人,也花了我一整天的时间来得到正确的,在现有的答案的帮助下。

对于一个多模块 Maven 项目:

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

其中 WAR项目是主要的网络应用程序,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>

WARLIBTEST 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 Plugin 为单元和集成测试创建代码覆盖报告”对于 JaCoCo 设置方面的东西很有价值。

自0.7.7版本以来的新方式

自从版本0.7.7以来,有一种创建聚合报告的新方法:

您创建了一个单独的“报告”项目,该项目收集所有必要的报告(聚合器项目中的任何目标都是执行 之前的,因此它的模块不能使用)。

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

根爆米花如下所示(不要忘记在模块下添加新的报表模块) :

<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 根本不需要更改。来自 报告单元的彩球看起来像这样:

<!-- 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>

完整的示例可以找到 给你

有一个办法可以做到。神奇的是创建一个组合的 jacoco.exec 文件。在 Maven3.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>

如果你把这个配置文件添加到你的家长和调用 mvn clean install sonar:sonar -DrunSonar你得到完整的覆盖面。

这里的神奇之处在于 maven.multiModuleProjectDirectory。这个文件夹始终是您开始构建专家版本的文件夹。

    <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>

这个样本对我来说非常有效:

<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>

由于声纳 sonar.jacoco.reportPathsonar.jacoco.itReportPathsonar.jacoco.reportPaths都是 不赞成,你现在应该使用 sonar.coverage.jacoco.xmlReportPaths。如果您希望使用 Sonar 和 Jacoco 配置多模块 maven 项目,那么这也会产生一些影响。

作为@Lonzak 指出,由于声纳0.7.7,您可以使用声纳报告聚集目标。只要把以下依赖关系放在你的父或母中就可以了:

<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 兼容,这将在它自己的目标文件夹中为 每个模块创建一个包含 jacoco.xml文件的 site/jacoco-total 文件夹。

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

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

为了保持我的答案简短和准确,我没有提到 maven-surefire-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>

我找到了另一个解决新的声纳版本,其中 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

你需要下面的 maven 构建插件配置在聚合项目的 POM:

<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>

然后与专家一起构建项目:

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/中的每个模块创建一个相对于每个模块的父目录的聚合报告。对于模块 A 和模块 B,这将是公共路径 moduleC/target/site/jacoco-aggregate/

由于模块 B 依赖于模块 A,所以模块 B 将在最后构建,其报告将在声纳中用作模块 A 和 B 的总覆盖率报告。

除了聚合报告之外,我们还需要一个普通的模块报告,因为 JaCoCo 聚合报告只包含依赖项的覆盖率数据。

这两种类型的报告一起为声纳提供完整的覆盖数据。

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

Jacoco Wiki所述,您还可以生成一个新的报告模块:

策略: 带依赖项的模块: 聚合器的问题 项目可以通过一个额外的“报告”模块来解决 多模块 Maven 项目定义了一个单独的模块,它不 提供实际内容,但创建一个合并的覆盖报告 中包含的所有模块的依赖项 「报告」模组会在其「合并报告」完成后才建立 并且可以访问 exec 文件以及 class 和 来自它所依赖的项目的源文件 最适合当前的 Maven 架构。从用户的角度来看 有人可能会说,这样一个单独的模块会使构建变得臃肿 或者,单独的模块不能有任何子模块 它可以从中使用 exec 或类文件 其他的策略,这些缺点似乎相当小,可以 以一致的方式处理。

如果您的模块化比一个父模块带有一些子模块更复杂,这尤其有帮助。

你的报告可能看起来像这样:

 <dependencies>
<dependency>
<groupId>org.sonarqube</groupId>
<artifactId>module1</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.sonarqube</groupId>
<artifactId>module2</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>


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