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

How to configure multi-module Maven + Sonar + JaCoCo to give merged coverage report?

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

这些答案,无论是单独还是组合使用,都是如何产生我所追求的:
覆盖率报告显示某个类是否在堆栈较高级别的测试中使用,例如DAO正在使用的实体,即使该类在其自己的模块中没有完全覆盖,也是如此。

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


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

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

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

1
2
3
4
5
6
7
<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中,即可为所有子模块运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<plugin>
    <groupId>org.jacoco</groupId>
    jacoco-maven-plugin</artifactId>
    <version>0.6.0.201210061924</version>
    <configuration>
        <destFile>${sonar.jacoco.reportPath}</destFile>
        true</append>
    </configuration>
    <executions>
        <execution>
            <id>agent</id>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
    </executions>
</plugin>

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

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


常问问题

自那时以来,我一直在脑海中发问,我对jacoco感到疯狂。

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

是。您必须使用以output=tcpserver模式运行的jacoco代理,即jacoco ant lib。基本上是两个jar。这将为您带来99%的成功。

jacoco代理如何工作?

您附加一个字符串

1
-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/中需要的是jacocoant.jar位于我的jenkins工作区中,而jacocoagent.jar位于我的应用程序服务器VM中吗?

那就对了。

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

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

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

.exec格式的coverage数据。声纳然后可以阅读它。

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

不,声纳有,但雅各科没有。当您执行mvn sonar:sonar时,类的路径就会起作用。

那蚂蚁脚本呢?

它必须显示在您的Jenkins工作区中。我的蚂蚁脚本,我称之为jacoco.xml看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<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构建。这是策略:

  • 调用ant目标jacocoReset以重置所有先前收集的数据。
  • 运行测试
  • 调用ant目标jacocoReport以获得报告
  • 如果一切正常,您将在构建工作区中看到it-jacoco.exec

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

    enter image description here

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

    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避免它。


    自0.7.7版以来的新方法

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

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

    1
    2
    3
    4
    5
    aggregator pom
      |- parent pom
      |- module a
      |- module b
      |- report module

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <build>
    <plugins>
      <plugin>
        <groupId>org.jacoco</groupId>
        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如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <!-- Add all sub modules as dependencies here -->
    <dependencies>
      <dependency>
        <module a>
      </dependency>
      <dependency>
        <module b>
      </dependency>
     ...

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
      <build>
        <plugins>
          <plugin>
            <groupId>org.jacoco</groupId>
            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>

    完整的示例可以在这里找到。


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

    对于多模块Maven项目:

    1
    2
    3
    4
    5
    ROOT
    |--WAR
    |--LIB-1
    |--LIB-2
    |--TEST

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

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

    ROOT pom.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    <!-- 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>
        jacoco-maven-plugin</artifactId>
        <version>0.7.6.201602180812</version>
        <executions>
            <execution>
                <id>agent-for-ut</id>
                <goals>
                    <goal>prepare-agent</goal>
                </goals>
                <configuration>
                    true</append>
                    <destFile>${sonar.jacoco.reportPath}</destFile>
                </configuration>
            </execution>
            <execution>
                <id>agent-for-it</id>
                <goals>
                    <goal>prepare-agent-integration</goal>
                </goals>
                <configuration>
                    true</append>
                    <destFile>${sonar.jacoco.itReportPath}</destFile>
                </configuration>
            </execution>
        </executions>
    </plugin>

    WARLIBTEST pom.xml将继承JaCoCo插件的执行。

    TEST pom.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        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} -Duser.timezone=UTC -Xms256m -Xmx256m</argLine>
                    <includes>
                        <includes>**/*Test*</includes>
                    </includes>
                </configuration>
            </execution>
        </executions>
    </plugin>

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


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    <profile>
        <id>runSonar</id>
       
            <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>
                    jacoco-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <id>default-prepare-agent</id>
                            <goals>
                                <goal>prepare-agent</goal>
                            </goals>
                            <configuration>
                                true</append>
                                <destFile>${jacoco.destFile}</destFile>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <groupId>org.sonarsource.scanner.maven</groupId>
                        sonar-maven-plugin</artifactId>
                        <version>3.2</version>
                    </plugin>
                    <plugin>
                        <groupId>org.jacoco</groupId>
                        jacoco-maven-plugin</artifactId>
                        <version>0.7.8</version>
                    </plugin>
                </plugins>
            </pluginManagement>
        </build>
    </profile>

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

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


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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
        <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下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
      <build>
         <pluginManagment>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    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>
                    maven-surefire-plugin</artifactId>
                    <version>2.19.1</version>
                    <configuration>
                        <forkCount>4</forkCount>
                        <reuseForks>false</reuseForks>
                        -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>
                    maven-failsafe-plugin</artifactId>
                    <version>2.19.1</version>
                    <dependencies>
                        <dependency>
                            <groupId>org.apache.maven.surefire</groupId>
                            surefire-junit47</artifactId>
                            <version>2.19.1</version>
                        </dependency>
                    </dependencies>
                    <configuration>
                        <forkCount>4</forkCount>
                        <reuseForks>false</reuseForks>
                        ${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>
                    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>
                                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>
                                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>
                ...

    在构建部分

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     <build>
         <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                maven-compiler-plugin</artifactId>
            </plugin>

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

    在报告部分

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
        <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                maven-surefire-report-plugin</artifactId>
                <version>${maven.surefire.report.plugin}</version>
                <configuration>
                    <showSuccess>false</showSuccess>
                    true</alwaysGenerateFailsafeReport>
                    true</alwaysGenerateSurefireReport>
                    true</aggregate>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.jacoco</groupId>
                jacoco-maven-plugin</artifactId>
                <version>${jacoco.plugin.version}</version>
                <configuration>
                    <excludes>
                        <exclude>**/*.mar</exclude>
                        <exclude>${jacoco.excludePattern}</exclude>
                    </excludes>
                </configuration>
            </plugin>
         </plugins>
      </reporting>


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

    假设我们的项目结构为:

    1
    2
    3
    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构建插件配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <plugin>
        <groupId>org.jacoco</groupId>
        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构建项目:

    1
    mvn clean verify

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

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

    或使用命令行:

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

    描述

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

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

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

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

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


    由于不推荐使用Sonars sonar.jacoco.reportPathsonar.jacoco.itReportPathsonar.jacoco.reportPaths,因此现在应该使用sonar.coverage.jacoco.xmlReportPaths。如果要使用Sonar和Jacoco配置多??模块Maven项目,这也会产生一些影响。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <plugin>
        <groupId>org.jacoco</groupId>
        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-aggregate文件夹。

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

    1
    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
    依赖项。您可以添加它们而无需任何其他配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        maven-surefire-plugin</artifactId>
        <version>2.22.2</version>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
        <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>
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
                <plugin>
                    <groupId>org.jacoco</groupId>
                    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>
                                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>
                                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>

    要进行单元测试和集成测试,可以使用包含受限/排除在内的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中,也许某些问题已在更高版本中得到解决


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

    如果要运行单元测试,请使用阶段准备包;如果要运行集成测试,请使用集成后测试。

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

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


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    <plugin>
                <groupId>org.jacoco</groupId>
                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>
                maven-surefire-plugin</artifactId>
                <version>2.18.1</version>
                <configuration>
                    ${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>
                maven-failsafe-plugin</artifactId>
                <version>2.12.4</version>
                <configuration>
                    <!--<skipTests>${skipTests}</skipTests>
                    <skipITs>${skipITs}</skipITs>-->
                    ${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>