Maven 构建中的代码覆盖率 - 由于缺少 类 目录而跳过 JaCoCo 执行

Code coverage in maven build - Skipping JaCoCo execution due to missing classes directory

如果我只有一个项目,但现在我有一个多模块项目,我能够使代码覆盖率正常工作。

我的应用程序是在 api 项目中构建的,我所有的集成测试都是 运行 在一个单独的项目中,该项目使用作为先前模块构建的工件。

构建运行但我没有收到代码覆盖率报告,而是收到信息消息:

Skipping JaCoCo execution due to missing classes directory

我的覆盖率报告文件 jacoco-it.exec 已创建,但似乎 jacoco 插件需要项目中的 类 测试在 运行 中。

有人能告诉我当 类 在另一个模块中时我需要做什么才能创建覆盖率报告吗?

经过反复试验,我设法找到了某种变通方法。

似乎 jacoco 插件很乐意在没有 类 的情况下创建 exec 文件,但没有它们它不会创建报告,我不明白 jacoco 是如何在内部工作的所以如果有人知道你能解释一下吗是吗?

我也不确定我所做的是否可靠,但它似乎确实报告了我的 selenium 驱动测试的覆盖率。

我自己想出的(可能的)解决方案是使用 maven 资源插件复制 类,它已从我的 target\cargo 中的 war 文件中展开..目录进入目录target\classes:

 <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.7</version>
        <executions>
          <execution>
            <id>copy-resources</id>             
            <phase>pre-integration-test</phase>
            <goals>
              <goal>copy-resources</goal>
            </goals>
            <configuration>
              <outputDirectory>${basedir}/target/classes</outputDirectory>
              <resources>          
                <resource>
                  <directory>${basedir}/target/cargo/configurations/tomcat7x/webapps/calculator-api/WEB-INF/classes</directory>
                  <filtering>false</filtering>
                  <excludes>
                        <exclude>**/*Config*.*</exclude>
                        <exclude>**/*Initialiser*.*</exclude>
                  </excludes>
                </resource>
              </resources>              
            </configuration>            
          </execution>
        </executions>
    </plugin>

这似乎让 jacoco 插件很开心,我得到了我的代码覆盖率,尽管插件现在似乎忽略了我的排除列表。

有谁知道这是否真的是一个解决方案,它 'seems' 可以工作,但我无法在网上找到任何推荐的方法,我也不确定为什么 jacoco 代理设置上的排除选项up 似乎不再有效。

我已经设法绕过 jacoco 插件不排除文件,只是不使用资源插件复制它们,但我仍然不明白 jacoco 是如何工作的。

您可以使用目标 jacoco:report-aggregate,它专门用于在单独的测试模块中创建覆盖率报告。

这是一个例子:

project
└─ module      ⇦ module with sources
└─ module-test ⇦ module with tests

那么你所要做的就是在 "module-test" 的 pom.xml 中使用这个目标 :

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

还要注意您在依赖项中使用的范围,如 docs 中所述。

尽管 jacoco:report-aggregate 用于聚合报告依赖关系,但它在我的情况下不起作用 - 我使用的项目结构如下:

project
└─ module-api   ⇦ API definition
└─ module-spec  ⇦ module with black box tests through the API
└─ module-impl1 ⇦ implementation 1 of the API
└─ module-impl2 ⇦ another implementation of the API
└─ module-test1 ⇦ some dependencies + impl1, apply the tests from spec
└─ module-test2 ⇦ some dependencies + impl2, apply the tests from spec

在这种情况下,report-aggregate 生成了一个空报告。 module-test1 和 module-test2 项目是POM封装类型,也不适合运行 report,因为需要在target/classes目录下类 .

我的解决方案

我将 jacoco 插件配置为 转储 类 it instruments 在项目的 target/classes 目录中添加: <classDumpDir>${project.build.outputDirectory}</classDumpDir>

这使得常规 report 目标得以实现。完整代码为:

<plugin>
  <groupId>org.jacoco</groupId>
  <artifactId>jacoco-maven-plugin</artifactId>
  <version>0.8.5</version>
  <configuration>
    <destFile>${project.build.directory}/coverage-reports/code-coverage.exec</destFile>
    <dataFile>${project.build.directory}/coverage-reports/code-coverage.exec</dataFile>
    <outputDirectory>${project.reporting.outputDirectory}/code-coverage</outputDirectory>
    <propertyName>jacocoArgLine</propertyName>
    <classDumpDir>${project.build.outputDirectory}</classDumpDir>
  </configuration>
  <executions>
    <execution>
      <id>prepare-jacoco-agent</id>
      <goals>
          <goal>prepare-agent</goal>
      </goals>
    </execution>
    <execution>
      <id>post-integration-test</id>
      <phase>post-integration-test</phase>
      <goals>
        <goal>report</goal>
      </goals>
    </execution>
  </executions>
</plugin>

请注意,已检测的 类 来自所有依赖项,因此需要进行一些过滤以缩小报告范围。参见:https://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html

我有类似的项目结构——主要代码在一个模块中,测试在另一个模块中——并且在 jacoco 报告中遇到了类似的问题。

我的解决方案1:

通过maven-resources-plugin/classes文件夹复制到测试模块。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <version>3.1.0</version>
    <executions>
       <execution>
         <id>copy-classes-to-test-module</id>
         <goals>
             <goal>testResources</goal>
         </goals>
         <configuration>
             <resources>
                 <resource>
                     <directory>${project.basedir}/../main-module/target/classes</directory>
                 </resource>
             </resources>
             <outputDirectory>
                    ${project.build.outputDirectory}
             </outputDirectory>
          </configuration>
        </execution>
     </executions>
</plugin>

但是如果你的代码中包含了lambdas, anonymous 类之类的,那么结果报告可能覆盖不了一些类,因为类会因为不同prepare-agent 运行。

我的方案二:

使用 report-aggregate 目标。

在父 POM 中,我有这样的配置:

<plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.8.3</version>
        <configuration>
            <append>true</append>
        </configuration>
        <executions>
            <execution>
                <id>prepare-agent</id>
                <goals>
                    <goal>prepare-agent</goal>
                </goals>
            </execution>
        </executions>
</plugin>

测试模块的 POM 包含这些行:

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

请记住,依赖范围对于 report-aggregate 目标 (jacoco docs) 很重要。如果您的测试模块只有测试范围的依赖项,您将得到一个空报告。因此,您应该将范围设置为编译、运行时或为您希望在报告中看到的那些工件提供。例如:

    <dependency>
        <groupId>my.project</groupId>
        <artifactId>main-module-classes</artifactId>
        <version>${project.version}</version>
        <scope>provided</scope>
    </dependency>