【问题标题】:How to configure multi-module Maven + Sonar + JaCoCo to give merged coverage report?如何配置多模块 Maven + Sonar + JaCoCo 以提供合并覆盖率报告?
【发布时间】:2012-10-13 10:20:25
【问题描述】:

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

在某种程度上,这些答案,无论是单独的还是组合的,都没有产生我所追求的东西: 覆盖率报告,如果在堆栈更高层的测试中使用某个类(例如 DAO 正在使用的实体),则显示该类已被覆盖,即使它没有被自己模块中的测试完全覆盖。

请问是否有明确的配置来实现这一点?

【问题讨论】:

    标签: maven code-coverage sonarqube jacoco


    【解决方案1】:

    我的情况和你一样,网上散落的一半答案很烦人,因为似乎很多人都有同样的问题,但没有人会费心解释他们是如何解决的。

    Sonar docs 指的是有用的a GitHub project with examples。我为解决这个问题所做的是将集成测试逻辑应用于常规单元测试(尽管正确的单元测试应该是特定于子模块的,但并非总是如此)。

    在父 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 放在父 pom 中的 build/plugins 中,即可为所有子模块运行:

    <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 中多模块文件的组合单元测试结果。

    【讨论】:

    • 太棒了!这已经奏效了。最后!我认为我缺少的魔法缺少重要咒语是true
    • 有效!在运行 mvn sonar:sonar 之前,我必须创建一个新的 mvn package 才能生成新的报告路径。
    • 根据示例,应该使用“sonar.jacoco.itReportPath”属性将合并结果转换为“整体代码覆盖率”。请更新答案。
    • "sonar.dynamicAnalysis" 也已弃用:docs.sonarqube.org/display/SONAR/Release+4.3+Upgrade+Notes
    【解决方案2】:

    自 0.7.7 版以来的新方式

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

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

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

    root pom 看起来像这样(不要忘记在 modules 下添加新的报告模块):

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

    每个子模块的 pom 根本不需要更改。 报告模块中的 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>
    

    完整的例子可以在here找到。

    【讨论】:

    • 这行得通。聚合报告显示所有模块的累积代码覆盖率。您是否曾尝试在 Sonar 中查看此累积报告?我使用 sonar-qube 读取 jacoco.exec 以获取单个报告,但使用此报告聚合,我在报告模块中看不到聚合的 jacoco.exec。
    • @SwethaV 这有什么成功吗?我们处于相同的位置,需要找到一种方法来生成聚合的 exec :)
    • 我们使用声纳 qube 版本 6.X,它有自己的测试覆盖页面,因此我不需要 jacoco。对于旧版本,我们安装了 cobertura 插件,该插件也提供了此功能...
    【解决方案3】:

    常见问题解答

    自从我对 jacoco 发疯以来,我脑海中浮现的问题。

    我的应用服务器(jBoss、Glassfish..)位于伊拉克、叙利亚等等。在其上运行集成测试时是否可以获得多模块覆盖? Jenkins 和 Sonar 也在不同的服务器上。

    是的。您必须使用以output=tcpserver 模式运行的jacoco agent,jacoco ant lib。基本上是两个jars。这将使您获得 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 插件如何帮助你。

    jacoco剂究竟产生了什么?

    .exec 格式的覆盖率数据。然后声纳可以读取它。

    jacoco 需要知道我的 java 类所在的位置吗?

    不,声纳可以,但 jacoco 不行。当您执行 mvn sonar:sonar 时,课程路径就会发挥作用。

    那么蚂蚁脚本呢?

    它必须呈现在您的 jenkins 工作区中。我的 ant 脚本,我叫它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 目标 jacocoReset 以重置所有之前收集的数据。
    2. 运行测试
    3. 调用蚂蚁目标jacocoReport获取报告

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

    看截图,我在$WORKSPACE/tools/ant dir 的工作区中也安装了ant,但您可以使用安装在jenkins 中的一个。

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

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

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

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

    【讨论】:

      【解决方案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
      

      对于声纳,您应该在管理 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 将最后构建,其报告将用作 Sonar 中模块 A 和 B 的聚合覆盖率报告。

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

      这两种类型的报告共同为 Sonar 提供了全覆盖数据。

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

      【讨论】:

      • 太棒了!终于找到了一种无需可怕的聚合器模块即可工作的方法!
      • 也许使用 ${maven.multiModuleProjectDirectory}/target/site/jacoco-aggregate/jacoco.xml 而不是 ../target/site/jacoco-aggregate/jacoco.xml 如果项目更多应该可以工作深度超过 1 级。需要 maven 3.3.1 或更新版本
      • 对我不起作用。我有多模块项目,子模块相互独立。在建议的更改之后,我可以在每个模块中看到单独的 jacoco 报告,但聚合模块的 jacoco.xml 是空的。我没有使用单独的聚合器模块并为此使用父模块。
      • 我尝试使用一个单独的模块进行聚合,并在那里为每个子模块提供依赖关系,它工作正常并生成聚合报告。但是给予依赖的问题是,根据我的发布周期,子模块的版本不断变化,并且这些版本对于每个子模块都是不同的。所以它在这里失败,因为我们不能在聚合模块中引用子模块版本,因为子模块不允许彼此共享属性。这里的任何帮助都会非常棒。谢谢
      【解决方案5】:

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

      对于多模块 Maven 项目:

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

      WAR 项目是主要 Web 应用程序,LIB 1 和 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 blog post 'Creating Code Coverage Reports for Unit and Integration Tests With the JaCoCo Maven Plugin' 对于 JaCoCo 设置方面很有价值。

      【讨论】:

      • 我需要在某个阶段更新这篇文章,因为它实际上有点不理想。 agent-for-it 仅在 TEST 模块中运行测试时才需要,但当前配置使其对所有其他模块都运行,它没有任何价值。改进是让agent-for-ut 在所有其他模块中运行,而agent-for-it 仅在TEST 中运行。
      【解决方案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 的文件夹。

      【讨论】:

      • 在经历了许多其他解决方案之后,这对我有用。
      • 唯一的问题是,由于A required class was missing while executing org.sonarsource.scanner.maven:sonar-maven-plugin:3.0.1:sonar: org/sonar/batch/bootstrapper/IssueListener 错误,我不得不使用命令mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.4.0.905:sonar -DrunSonar 运行声纳。
      • 不要使用这个魔法。给定的属性是一个实现细节,不应依赖。 -- Maven 开发团队
      【解决方案7】:

      我在父级 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 以在每个测试中运行。

      在插件管理下

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

      【讨论】:

      • 我看到你在prepare-agent 部分下有&lt;append&gt;true&lt;/append&gt; 配置...
      • 强调。阅读我对另一个答案的评论。它是我缺少的重要成分,在其他文档中找不到。
      • 你有这个的github链接吗?我想做完全相同的配置
      • @Rhit - 不,我没有,至少不在公共存储库中。
      • 这适用于 Sonar Qube 版本 6.5 (build 27846) ... :D 代码覆盖率将正确显示。
      【解决方案8】:

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

      作为@Lonzak pointed out,从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 兼容,这将为 每个 模块在其自己的目标文件夹中创建一个包含 @987654328 的 site/jacoco-aggregate 文件夹@文件。

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

      【讨论】:

        【解决方案9】:
            <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>             
        

        【讨论】:

          【解决方案10】:

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

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

          This site 有一个例子说明如何在 maven 项目中调用 jacoco ant 任务

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

          【讨论】:

            【解决方案11】:

            要进行单元测试和集成测试,您可以使用 maven-surefire-plugin 和 maven-failsafe-plugin 以及受限的包含/排除。我在与 sonar/jacoco 联系时正在玩 CDI,所以我最终参与了这个项目:

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

            也许对你有一点帮助。在我的 pom.xml 中,我通过在指定测试插件的配置部分中设置 argLine 选项来隐式使用“-javaagent”。 在 MAVEN 项目中明确使用 ANT 是我不会尝试的,对我来说,它混合了两个世界。

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

            注意:也许不是所有的 maven 插件都是最新的,也许一些问题在以后的版本中得到了修复

            【讨论】:

            • 谢谢你;我会看看,让你知道它是如何工作的。不过可能不是这周:)
            【解决方案12】:

            这个示例对我来说效果很好:

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

            【讨论】:

            【解决方案13】:

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

            策略:具有依赖关系的模块:聚合器的问题 项目可以通过额外的“报告”模块来解决。在一个 多模块 Maven 项目定义了一个单独的模块,不 贡献实际内容,但创建一个综合报道报告。它 定义了对所有应该包含在 合并报告。 “报告”模块将在其之后构建 依赖项并可以访问 exec 文件以及类和 它依赖的项目的源文件。这个策略似乎奏效 最适合当前的 Maven 架构。从用户的角度 有人可能会争辩说,这样一个单独的模块会使构建膨胀 定义。或者,单独的模块不能有任何子模块 它可以从中使用 exec 或 class 文件。然而,相比 其他策略这些缺点似乎相当小,可以 以一致的方式处理。

            如果您的模块化比具有一些子模块的父级更复杂,这将特别有用。

            您的报告 pom 可能类似于:

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

            【讨论】:

            • 这里只有一个问题。如果我们的子模块的版本不固定并随着版本不断变化怎么办。而且它们是不一致的,这意味着 module1 在 1.5 上,而 module2 在 3.6 上,所以我们不能做一个项目。版本或父 .project.version。此外,子模块的 POM 无法交互和获取依赖版本。您对如何解决这个问题有任何想法吗?
            猜你喜欢
            • 2013-03-16
            • 2013-02-07
            • 2014-08-29
            • 1970-01-01
            • 2019-03-16
            • 1970-01-01
            • 2012-10-16
            • 2018-09-09
            • 1970-01-01
            相关资源
            最近更新 更多