Подтвердить что ты не робот

Невозможно использовать jacoco JVM args и surefire JVM args вместе в maven

Я использую maven с плагином jacoco для генерации метрик покрытия кода. У меня возникли трудности с настройкой плагина surefire с параметрами java, требуемыми плагином jacoco. Я уже видел некоторые ответы об этом на 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 для получения метрик покрытия кода, поэтому я добавил профиль CodeCoverage, который обрабатывает всю конфигурацию jacoco:

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, и это свойство используется для настройки argLine для плагина surefire.

Затем я обновил файл pom.xml для модуля foo, чтобы использовать свойство surefire.argLine, сгенерированное плагином jacoco:

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

Когда я создаю модуль foo с профилем 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 = -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 использует свойство surefire.argLine и локальный аргумент MaxPermSize, и создается файл 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>

Теперь, когда я создаю модуль foo без использования профиля CodeCoverage, я не получаю ошибок:

[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) и не существует каталога 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, фактически используется для создания argline для плагина surefire.

В результате нет файла jacoco-ut.exec и no target\code-coverage, когда я использую профиль CodeCoverage.

Я не уверен, что я делаю неправильно здесь. Я объявляю свойство argLine, как было предложено в документации jacoco, и использую его, когда плагин surefire должен указать дополнительный аргумент. Другие ответы на Qaru предлагают создать свойство с тем же именем, что и свойство jacoco argLine, чтобы обрабатывать случай, когда jacoco не вызывается.

Любые предложения?

изменить

Возможно, одним из решений является явно объявить свойство surefire.argLine в профиле CodeCoverage и забыть об использовании argLine плагина jacoco:

<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, чтобы использовать java-агент, требуемый плагином jacoco, и настроить плагин surefire для использования этого свойства для своих аргументов JVM. Плагин jacoco теперь создаст свойство argLine, но это будет проигнорировано. Это не изящное решение (поскольку я делаю предположения о том, как работает плагин jacoco, и это может измениться в будущей версии).

изменить

Свойство jacoco.agent.jar также должно быть установлено путем указания его местоположения в локальном репозитории (не уверен, является ли это надежным) или с помощью плагина зависимостей для копирования jaroco 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

4b9b3361

Ответ 1

Поскольку цель jacoco-maven-plugin:prepare-agent выполняется перед плагином maven-surefire, попробуйте добавить переменную ${argLine} в значение argLine, установленное плагином maven-surefire.

Пример:

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

Ответ 2

Попробуйте использовать

@{argLine}

вместо

${argLine}

(или surefire.argLine в вашем случае)

Он позволяет surefire читать свойство, модифицированное другими плагинами, вместо того, чтобы читать тот, который заменяет сам Maven. Затем вы можете установить параметр argLine для пустых свойств Maven:

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

Что теперь не вызовет никаких проблем. Подробнее здесь: Как использовать свойства, установленные другими плагинами в argLine?

Ответ 3

Если ваш проект уже использует argLine для настройки плагина surefire-maven, убедитесь, что 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

Ответ 4

Попробуйте добавить свойство 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

Ответ 5

Недавно я столкнулся с одной и той же проблемой и даже сделал неявно те же шаги, которые вы описали с тем же результатом. Никакого чистого решения, которое я нашел, не работало для меня.

Итак, я выполнил несколько шагов в режиме отладки, и кажется, что Maven дважды заменяет свойства. Это не просто лениво, как я думал, но как с нетерпением и ленивым образом:

  • с нетерпением (до запуска любой цели) заменяются статические свойства (определенные в разделе properties POM и, возможно, также settings.xml),
  • лениво (перед каждым исполнением) заменяются динамические.

Здесь наш шаг с установкой пустого свойства по умолчанию не выполнен. Maven только что пошел:

  • заменить значение по умолчанию (пустое)
  • JaCoCo устанавливает динамическое значение
  • ленивая замена динамических значений (теперь ничего заменить, уже использовалось пустое значение)

Наконец, решение состоит в том, чтобы динамически устанавливать значение по умолчанию. Это можно сделать с помощью плагина 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 идет:

  • надежная замена статических свойств
  • GMaven динамически устанавливает значение по умолчанию (если профиль активен)
  • JaCoCo устанавливает динамическое значение
  • Surefire работает с правильно установленным argLine

С активным профилем создается файл exec, при неактивном профиле используется пустое значение по умолчанию, и сборка завершается успешно.

Ответ 6

Мое решение - использовать несколько профилей.

Первый профиль устанавливает пустое значение для surefire.argLine и failsafe.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>

Когда вы активируете профиль сонара, профиль не-сонара автоматически отключится.

Это должно быть немного более элегантным, чем использование других плагинов для выполнения этой работы. Теперь вы можете использовать переменную ${surefire.argLine} в вашей 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>

Ответ 7

Мое решение для безопасного использования argLine в плагине maven-surefire.

<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 (для сонара) утверждает, что argline должен быть добавлен как свойство. Для меня это также работает при использовании @{argLine} в настройках плагина surefire.