【问题标题】:Cannot use jacoco JVM args and surefire JVM args together in maven不能在 maven 中同时使用 jacoco JVM args 和 surefire JVM args
【发布时间】:2014-06-05 02:05:54
【问题描述】:

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

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

foo/pom.xml:

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

这按预期工作。

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

parent/pom.xml:

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

这里看到如果指定了CodeCoverage配置文件,那么jacoco插件被配置为使用surefire.argLine属性,该属性用于配置surefire 插件的argLine

然后我更新了 foo 模块的 pom.xml 文件以使用 jacoco 插件生成的surefire.argLine 属性:

foo/pom.xml:

<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])。

当我使用 CodeCoverage 配置文件构建 foo 模块时,我看到以下内容:

[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 属性被创建,surefire 插件的argLine 使用surefire.argLine 属性和本地@ 987654336@ 参数,并按预期生成target\code-coverage\jacoc-ut-exec 文件。

但是,如果我不使用 CodeCoverage 配置文件,则会收到错误消息,因为 ${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}`

Sinec 没有调用 jacoco 插件,没有创建 surefire.argLine 属性,因此出现错误。

所以,我回到parent/pom.xml 并创建这个属性,没有初始值:

parent/pom.xml:

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

现在,当我在不使用 CodeCoverage 配置文件的情况下构建 foo 模块时,我没有收到任何错误:

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

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

所以现在我回到生成代码指标,使用 CodeCoverage 配置文件:

[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属性,但是surefire.argLine属性在parent/pom.xml文件中定义的空值实际上是用来为 surefire 插件创建 argline。

因此,当我使用 CodeCoverage 配置文件时,没有jacoco-ut.exec 文件和target\code-coverage 目录。

我不确定我在这里做错了什么。我按照 jacoco 文档的建议声明了一个 argLine 属性,并在 surefire 插件需要指定其他参数时使用它。 Stack Overflow 上的其他答案建议创建一个与 jacoco argLine 属性同名的属性,以处理未调用 jacoco 的情况。

有什么建议吗?

编辑

也许一种解决方案是在 CodeCoverage 配置文件中显式声明 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>

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

编辑

jacoco.agent.jar 属性也必须设置,通过指向其在本地存储库中的位置(不确定这是否可靠)或使用 dependency 插件复制 jacoco 代理 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>

编辑

不确定使用 dependency 插件是否是正确的方法,或者指向本地存储库中的 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

【问题讨论】:

标签: maven jacoco maven-surefire-plugin


【解决方案1】:

尝试在属性部分添加 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

【讨论】:

  • 这和一开始不包含${argLine}的效果一样,makind jacoco不产生输出
  • 那个页面不存在了,新的说:Deprecated since Java Plugin version 2.4直接嵌入了JaCoCo的支持。
【解决方案2】:

由于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 的其他部分。

【讨论】:

    【解决方案3】:

    我最近遇到了同样的问题,甚至隐含地采取了与您描述的相同的步骤,结果相同。我没有找到适合我的干净解决方案。

    所以我在调试模式下运行了几个步骤,似乎 Maven 替换了两次属性。这不仅是一种懒惰的方式,正如我所想的那样,而且是急切和懒惰的方式:

    1. 急切(在运行任何目标之前)被替换为 static 属性(在 POM 的 properties 部分中定义,可能还有 settings.xml),
    2. lazily(在每次执行之前)被替换为 dynamic 属性。

    这是我们将空白属性设置为默认值的步骤失败的地方。 Maven 刚刚去了:

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

    最后的解决方案是动态设置默认值。这可以使用 GMaven 插件来完成,如下所示:

    <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. Surefire 使用正确设置的 argLine 运行

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

    【讨论】:

    • 有趣的解决方案。我需要试试这个。
    【解决方案4】:

    尝试使用

    @{argLine}
    

    而不是

    ${argLine}
    

    (或 surefire.argLine 在你的情况下)

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

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

    现在不会造成任何问题。更多内容:How do I use properties set by other plugins in argLine?

    【讨论】:

    • 这对我来说非常有效,但不幸的是,一些 IDE(即 IntellJ 最高 14.1.4)似乎有问题 - 例如stackoverflow.com/q/24115142/3281722中报告的
    • IntelliJ 用户可以找到解决方案here
    • Intellij 版本 2017.2 对此没有任何问题,对我来说,修复比更高级的要简单得多。
    • @ 语法记录在哪里?我过去使用${argLine}&lt;properties&gt; 中的默认值,它工作得很好。为什么我需要@{argLine}
    • @Gili Per the maven-surefire-plugin FAQ 链接在答案中:“Maven 在运行任何插件之前对pom.xml 中的${...} 值进行了属性替换。所以Surefire 永远不会在其中看到占位符argLine 属性。由于版本 2.17 使用这些属性的替代语法,@{...} 允许在执行插件时延迟替换属性,因此将正确拾取已被其他插件修改的属性。"
    【解决方案5】:

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

    第一个配置文件为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>
    

    【讨论】:

      【解决方案6】:

      如果您的项目已经使用 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

      【讨论】:

      • 在本页上述所有其他解决方案都失败后,这对我有用!
      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

        对我来说,将版本从 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
        

        jacoco plugin site (for sonar) 声明 argline 必须作为属性添加。对我来说,在surefire插件设置中使用@{argLine}时也可以使用。

        【讨论】:

          【解决方案9】:

          我添加了一个Maven/Java project,其中包含 1 个具有以下功能的域类:

          • 单元或集成测试,使用插件 Surefire 和 Failsafe。
          • 查找错误。
          • 通过 Jacoco 测试覆盖率。

          我使项目尽可能简单。该项目将来自这些和其他帖子的许多建议放在一个示例项目中。谢谢贡献者!

          自述文件提供了简要说明。它解释了如何使用 Jacoco 运行用户或集成测试。

          享受吧!

          【讨论】:

          • 这个项目在这里有什么帮助?它在 2019-06 不起作用
          【解决方案10】:

          将 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 项目: mvn jacoco:prepare-agent clean test jacoco:report

          【讨论】:

            猜你喜欢
            • 2010-10-05
            • 1970-01-01
            • 2013-05-10
            • 2019-09-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多