不能在 maven 中一起使用 jacoco JVM args 并确保 JVM args 被激活

我使用了带有 Jacoco插件的 maven 来生成代码覆盖度量。我在使用 Jacoco插件所需的 java 选项配置 当然插件时遇到了一些困难。我已经在 Stack Overflow 上看到了一些关于这个问题的答案,但是有些东西对我不起作用。

我有一个多模块的项目,我的一个模块配置的 当然插件如下:

返回文章页面

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-XX:MaxPermSize=512m</argLine>
</configuration>
</plugin>
</plugins>

一切如我所料。

现在我想合并 jacoco 来获得代码覆盖度量,所以我添加了一个 代码覆盖率配置文件来处理所有的 jacoco 配置:

返回文章页面

<profile>
<id>CodeCoverage</id>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals><goal>prepare-agent</goal></goals>
<configuration>
<propertyName>surefire.argLine</propertyName>
</configuration>
...
</execution>
<executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>

这里可以看到,如果指定了 代码覆盖率配置文件,那么 Jacoco插件就被配置为使用 surefire.argLine属性,并且该属性用于为 当然插件配置 argLine

然后,我更新了 模块的 Pom.xml文件,使用 Jacoco插件生成的 surefire.argLine属性:

返回文章页面

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>${surefire.argLine} -XX:MaxPermSize=512m</argLine>
</configuration>
</plugin>
</plugins>

这种方法在 Jacoco插件文档中有详细说明(参见[1])。

当我使用 代码覆盖率配置文件构建 模块时,我看到以下内容:

[foo] $ mvn clean install -X -PCodeCoverage
...
[INFO] --- jacoco-maven-plugin:0.7.0.201403182114:prepare-agent (jacoco-initialize) @ foo ---
[INFO] surefire.argLine set to -javaagent:...\\org.jacoco.agent\\0.7.0.201403182114\\org.jacoco.agent-0.7.0.201403182114-runtime.jar=destfile=...\foo\\\target\\coverage-reports\\jacoco-ut.exec
...
[DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator -->
[DEBUG]   (s) argLine = -javaagent:...\\org.jacoco.agent\\0.7.0.201403182114\\org.jacoco.agent-0.7.0.201403182114-runtime.jar=destfile=...\\foo\\target\\coverage-reports\\jacoco-ut.exec -XX:MaxPermSize=512m
...
[INFO] --- jacoco-maven-plugin:0.7.0.201403182114:report (jacoco-site) @ foo ---
[INFO] Analyzed bundle 'Foo' with 59 classes`

因此,执行 Jacoco插件,创建一个 surefire.argLine属性,当然插件的 argLine使用 surefire.argLine属性和本地 MaxPermSize参数,然后像预期的那样生成一个 target\code-coverage\jacoc-ut-exec文件。

但是,如果我没有使用 代码覆盖率配置文件,那么我会得到一个错误,因为 ${surefire.argLine}属性(在 foo/pom.xml中使用)不是由 Jacoco插件创建的,也没有在任何地方定义:

[foo] $ mvn clean install -X
...
[DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator -->
[DEBUG]   (s) argLine = ${surefire.argLine} -XX:MaxPermSize=512m
...
Error: Could not find or load main class ${surefire.argLine}`

因为没有调用 Jacoco插件,所以没有创建 surefire.argLine属性,所以出现了错误。

因此,我返回到 parent/pom.xml并创建这个属性,它没有初始值:

返回文章页面

<properties>
<surefire.argLine></surefire.argLine>
</properties>

现在,当我在没有使用 代码覆盖率概要文件的情况下构建 模块时,我不会得到任何错误:

[foo] $ mvn clean install -X
...
[DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator -->
[DEBUG]   (s) argLine =  -XX:MaxPermSize=512m
...
[INFO] BUILD SUCCESS`

现在,当然 argline 是正确的(使用空的 surefire.argLine属性) ,并且没有 target\code-coverage目录,正如预期的那样。

因此,现在我回过头来使用 代码覆盖率概要文件生成代码度量:

[foo] $ mvn clean install -X -PCodeCoverage
...
[INFO] --- jacoco-maven-plugin:0.7.0.201403182114:prepare-agent (jacoco-initialize) @ foo ---
[INFO] surefire.argLine set to -javaagent:...\\org.jacoco.agent\\0.7.0.201403182114\\org.jacoco.agent-0.7.0.201403182114-runtime.jar=destfile=...\\foo\\target\\coverage-reports\\jacoco-ut.exec
...
[DEBUG] Configuring mojo 'org.apache.maven.plugins:maven-surefire-plugin:2.13:test' with basic configurator -->
[DEBUG]   (s) argLine =  -XX:MaxPermSize=512m
...
[INFO] --- jacoco-maven-plugin:0.7.0.201403182114:report (jacoco-site) @ foo ---
[INFO] Skipping JaCoCo execution due to missing execution data file:...\foo\target\coverage-reports\jacoco-ut.exec

这里可以观察到,Jacoco插件被调用并设置了 surefire.argLine属性,但是在 parent/pom.xml文件中定义了空值的 surefire.argLine属性实际上被用来为 当然插件创建 argline。

因此,在使用 代码覆盖率配置文件时,不存在 jacoco-ut.exec文件和 target\code-coverage目录。

我不知道我哪里做错了。我正在按照 Jacoco文档的建议声明一个 argLine属性,并在 当然插件需要指定附加参数时使用它。关于 Stack Overflow 的其他答案建议创建一个与 Jacoco argLine 属性同名的属性,以便在未调用 Jacoco时处理这种情况。

有什么建议吗?

编辑

也许一种解决方案是在 代码覆盖率配置文件中显式声明 surefire.argLine属性,而忘记使用 Jacoco插件的 argLine:

<profile>
<id>CodeCoverage</id>
<properties>
<surefire.argLine>-javaagent:${jacoco.agent.jar}=destfile=${jacoco.report.path}</surefire.argLine>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>jacoco-initialize</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<!-- no longer specifying 'argLine' for jacoco plugin ... -->
</execution>
<executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- ... instead the arg line is configured explicitly for surefire plugin. -->
<argLine>${surefire.argLine}</argLine>
</configuration>
</plugin>
</plugins>
</plugin>
</build>

这将创建使用 Jacoco插件所需的 java 代理的 当然可以 argLine属性,并将 当然插件配置为将该属性用于其 JVM 参数。Jacoco插件现在将创建一个 ArgLine属性,但这将被忽略。这不是一个优雅的解决方案(因为我对 Jacoco插件的工作方式做了一些假设,这可能会在将来的版本中改变)。

编辑

还必须通过指向其在本地存储库中的位置(不确定这是否健壮)或使用 依赖性插件将 Jacoco代理 jar 复制到本地构建目录来设置 jacoco.agent.jar属性:

<profile>
<id>CodeCoverage</id>
<properties>
<jacoco.agent.jar>${project.build.directory}/jacoco-agent.jar</jacoco.agent.jar>
...
</project>
<build>
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>download-jacoco-agent</id>
<phase>process-test-resources</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<version>${jacoco.version}</version>
<classifier>runtime</classifier>
<outputDirectory>${project.build.directory}</outputDirectory>
<destFileName>jacoco-agent.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>

编辑

不确定使用 依赖性插件是否是正确的方法,或者指向本地存储库中的 jacoco 代理构件:

<profile>
<id>CodeCoverage</id>
<properties>
<jacoco.agent.jar>${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco.version}/org.jacoco.agent-${jacoco.version}-runtime.jar</jacoco.agent.jar>
</properties>
...
</profile>

这更简单,而且不需要将工件复制到本地构建目录,但是很脆弱: 存储库布局的更改将破坏这一点。

[1] http://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html

62147 次浏览

尝试在属性部分添加 argLine 属性(如下面的代码所示) ,而不是将其添加到 maven-sure-fire 插件的配置部分。Jacoco maven 插件将只是附加到这一点,事情将按照预期工作。

<properties>
<argLine>-XX:MaxPermSize=512m</argLine>
</properties>

参见 https://docs.sonarqube.org/display/PLUG/Usage+of+JaCoCo+with+Java+Plugin

因为 jacoco-maven-plugin:prepare-agent目标在 maven-surefire-plugin 之前执行,所以尝试将 ${argLine}变量添加到 maven-surefire-plugin 设置的 argLine值中。

例如:

<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.1</version>
<configuration>
<argLine>-server -ea -XX:MaxPermSize=256m -Xmx4g -XX:-UseSplitVerifier ${argLine}</argLine>
</configuration>
</plugin>

我遇到了同样的问题,这个解决方案对我很有效,不需要重新配置 POM 的其他部分。

我最近遇到了同样的问题,甚至采取了您所描述的隐式相同的步骤,得到了相同的结果。我找不到合适的解决办法。

因此,我在调试模式下运行了几个步骤,似乎 Maven 替换了两次属性。这不像我想的那样只是一种懒惰的方式,而是既热切又懒惰的方式:

  1. 热切地 (在运行任何目标之前)被替换为 静电干扰属性(在 POM 的 properties部分中定义,可能还有 setings.xml) ,
  2. 惰性 (在每次执行之前)被替换为 充满活力属性。

这就是我们设置空白属性为默认属性的步骤失败的地方:

  1. 默认值(空白)的急切替换
  2. JaCoCo 设置动态值
  3. 动态值的延迟替换(现在没有什么可替换的,已经使用了空值)

最后,解决方案是动态设置默认值:

<plugin>
<groupId>org.codehaus.gmaven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>set-default-values</id>
<phase>initialize</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
project.properties.'surefire.argLine' = ''
</source>
</configuration>
</execution>
</executions>
</plugin>

所以现在 Maven 说:

  1. 静态属性的即时替换
  2. GMaven 动态设置默认值(如果配置文件是活动的)
  3. JaCoCo 设置动态值
  4. 使用正确设置的 argLine 运行 Surefire

对于活动配置文件,将生成 exec 文件,对于非活动配置文件,将使用空白默认值并成功构建。

尝试使用

@{argLine}

而不是

${argLine}

(或 surefire.argLine)

它允许 surefire 读取由其他插件修改的属性,而不是读取由 Maven 本身替代的属性。然后,您可以将 argLine参数设置为 Maven 属性中的空值:

<properties>
<argLine></argLine>
</properties>

现在不会造成任何问题。更多内容请看: 如何使用 argLine 中其他插件设置的属性?

我的解决方案是使用多个配置文件。

第一个配置文件为 surefire.argLinefailsafe.argLine设置一个空白值,默认情况下是活动的。

<profile>
<id>not-sonar</id>
<properties>
<surefire.argLine/>
<failsafe.argLine/>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>

第二个配置文件具有 Jacoco 插件配置,默认情况下是非活动的。

<profile>
<id>sonar</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin-version}</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<propertyName>surefire.argLine</propertyName>
</configuration>
</execution>
<execution>
<id>default-prepare-agent-integration</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<propertyName>failsafe.argLine</propertyName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>

当您激活声纳配置文件的非声纳配置文件将自动关闭。

这应该比使用其他插件为您完成工作更优雅一些。现在可以在 argLine 中使用 ${surefire.argLine}变量,它将始终存在,并在运行生成时设置它。

  <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>${surefire.argLine} -XX:MaxPermSize=512m</argLine>
</configuration>
</plugin>

如果因为 ${ surefire.argLine }没有值而仍然存在问题,您也可以像下面这样设置一个虚拟属性:

<profile>
<id>not-sonar</id>
<properties>
<surefire.argLine>-DdummyProperty=notUsed</surefire.argLine>
<failsafe.argLine>-DdummyProperty=notUsed</failsafe.argLine>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>

如果您的项目已经使用 argLine 来配置 surefire-maven-plugin,确保 argLine 定义为一个属性,而不是插件配置的一部分:

  <properties>
<argLine>-your -extra -arguments</argLine>
</properties>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- Do not define argLine here! -->
</configuration>
</plugin>

结果覆盖率信息将在执行期间收集,并在缺省情况下在进程终止时写入文件。

对我有用,看: http://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html

在 maven-surefire-plugin 中安全使用 argLine 的解决方案。

<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>2.0</version>
<executions>
<execution>
<id>set-custom-arg-line</id>
<phase>validate</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<source>
def argLine = project.properties['argLine'];
if (argLine == null) {
argLine = "";
}
project.properties.argLine = argLine;
</source>
</configuration>
</execution>
</executions>
</plugin>


<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<argLine>-Xmx1024m ${argLine}</argLine>
</configuration>
</plugin>

对我来说,从0.7.7.201606060606升级到0.7.9版本也修复了这个问题。

我必须显式地将版本添加到命令行(而不仅仅是添加到 pom) ,因为构建服务器一直在使用旧版本。可以这样做:

 org.jacoco:jacoco-maven-plugin:0.7.9:prepare-agent

而不是

org.jacoco:jacoco-maven-plugin:prepare-agent

雅可可(声纳)插件网站指出,必须将 argline 作为属性添加。对我来说,它也工作时,使用的 @{argLine}在必胜的插件设置。

我已经添加了一个带有1个域类的 Maven/Java 项目,它具有以下特性:

  • 单元或集成测试 与插件。
  • 臭虫。
  • 通过 雅科科测试覆盖率。

我尽可能简化了这个项目。该项目将来自这些和其他职位的许多建议放在一个示例项目中。谢谢你们,贡献者们!

自述文件给出了一个简短的解释。它解释了如何使用 雅科科运行用户测试或集成测试。

好好享受吧!

将 POM.xml 更新为

<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.7.201606060606</version>
<executions>
<execution>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>


<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.1</version>
<configuration>
<argLine>${argLine} -XX:PermSize=256m -XX:MaxPermSize=1048m</argLine>
</configuration>
</plugin>

然后最重要的事情就是带着目标运行 Maven 项目: 准备-代理清洁试验