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

Невозможно заставить Jacoco работать с Powermockito, используя автономную аппаратуру

Учитывая, что Jacoco не играет хорошо с PowerMockito, когда инструмент "на лету", я пытаюсь настроить автономную аппаратуру в надежде, что это даст мне правильный охват unit test для классов, которые используют PowerMockito.

Я установил мой pom, как показано ниже, но я все равно получаю нулевое покрытие на своем тестовом классе. Любая помощь очень ценится, поскольку это заставляет меня медленно бегать!

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>mandy</groupId>
    <artifactId>jacoco-test</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>jacoco-test Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <properties>
        <powermock.version>1.5.4</powermock.version>
        <jacoco.version>0.7.1.201405082137</jacoco.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.jacoco</groupId>
            <artifactId>org.jacoco.agent</artifactId>
            <classifier>runtime</classifier>
            <version>${jacoco.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>${powermock.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito</artifactId>
            <version>${powermock.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco.version}</version>
                <executions>
                    <execution>
                        <id>instrument</id>
                        <phase>process-classes</phase>
                        <goals>
                            <goal>instrument</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>restore-report</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>restore-instrumented-classes</goal>
                            <goal>report</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.17</version>
                <configuration>
                    <!--<argLine>${argLine}</argLine>-->
                    <systemPropertyVariables>
                        <!-- JaCoCo runtime must know where to dump coverage: -->
                        <jacoco-agent.destfile>target/jacoco.exec</jacoco-agent.destfile>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
        </plugins>
        <finalName>jacoco-test</finalName>
    </build>
</project>

здесь находится мой класс:

public class Utils {

    private Utils() {

    }

    public static String say(String s) {
        return "hello:"+s;
    }
}

вот мой тест:

@RunWith(PowerMockRunner.class)

@PrepareOnlyThisForTest(Utils.class)
@PowerMockIgnore("org.jacoco.agent.rt.*")
public class UtilsTest {

    @Test
    public void testSay() throws Exception {
        PowerMockito.mockStatic(Utils.class);
        Mockito.when(Utils.say(Mockito.anyString())).thenReturn("hello:mandy");
        assertEquals("hello:mandy", Utils.say("sid"));
    }

}

Я запускаю mvn clean install, который генерирует jacoco.exe

Отчет о покрытии (созданный с помощью jacoco.exec с помощью ant script): -

Coverage report

4b9b3361

Ответ 1

Этот пом работал для меня:

 <build>
    <finalName>final-name</finalName>
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.18.1</version>
            <configuration>
                <systemPropertyVariables>
                    <jacoco-agent.destfile>target/jacoco.exec</jacoco-agent.destfile>
                </systemPropertyVariables>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.jacoco</groupId>
            <artifactId>jacoco-maven-plugin</artifactId>
            <version>0.7.2.201409121644</version>
            <executions>
                <execution>
                    <id>default-instrument</id>
                    <goals>
                        <goal>instrument</goal>
                    </goals>
                </execution>
                <execution>
                    <id>default-restore-instrumented-classes</id>
                    <goals>
                        <goal>restore-instrumented-classes</goal>
                    </goals>
                </execution>
                <execution>
                    <id>default-report</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>report</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Смотрите эту ссылку.

Ответ 2

Я видел одно и то же поведение, хотя после того, как после потока по проблеме GitHub, похоже, он исправлен в 1.6.5, что оказалось верным для меня.

Надеюсь, это спасет кого-то головную боль позже:).

Рабочая конфигурация с:

  • jacoco-maven-plugin 0.7.7.201606060606
  • powermock 1.6.5

Я не использую автономную аппаратуру.

Ответ 3

Я заставил это работать, используя javaagent PowerMock. смотрите здесь: https://github.com/powermock/powermock/wiki/PowerMockAgent

Удалите аннотации @RunWith, поместите PowerMockRule, как описано в ссылке выше. Сделайте это публичным.

Поместите следующую строку в конфигурацию maven-surefire-plugin:

-javaagent:${org.powermock:powermock-module-javaagent:jar}

(Использовал метод, описанный здесь: Могу ли я использовать путь к зависимости Maven как свойство?)

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.stackoverflow</groupId>
    <artifactId>q2359872</artifactId>
    <version>2.0-SNAPSHOT</version>
    <name>q2359872</name>

    <properties>
        <!-- Must be listed in the dependencies section otherwise it will be null. -->
        <my.lib>${org.jmockit:jmockit:jar}</my.lib>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.jmockit</groupId>
            <artifactId>jmockit</artifactId>
            <version>1.11</version>
        </dependency>
    </dependencies>
    <build>
        <defaultGoal>generate-sources</defaultGoal>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>properties</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!-- Example usage: -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                        <phase>generate-sources</phase>
                    </execution>
                </executions>
                <configuration>
                    <executable>echo</executable>
                    <arguments>
                        <argument>path to jar=</argument>
                        <argument>${org.jmockit:jmockit:jar}</argument>
                        <argument>my.lib=</argument>
                        <argument>${my.lib}</argument>
                    </arguments>
                </configuration>
            </plugin>
            <!-- end of Example usage -->
        </plugins>
    </build>
</project> 

Ответ 4

Я тоже столкнулся с той же проблемой. Я смог создать отчет частично. Я использовал оба эти тега для своих тестовых примеров @RunWith (PowerMockRunner.class) @Готовиться к экзамену({}). И отчет не генерировался для тестовых случаев, когда я использовал вышеупомянутые теги. Но для одного из тестовых примеров был только этот тег @RunWith (PowerMockRunner.class). Так или иначе, отчет был создан для этого случая. А также я никогда не использовал автономную аппаратуру. Когда я пытался использовать автономную аппаратуру, я получал ошибку, говоря, что класс уже был инструментальным. Я пробовал различные сценарии и следил за различными ссылками, но не смог создать отчет. Наконец, согласно вышеприведенному комментарию, я обновил мою версию powermock с 1.5.5 до 1.6.5, и я смог создать отчет. Ниже приведена запись pom.xml

     <plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.7.5.201505241946</version>
    <executions>
        <execution>
            <id>pre-unit-test</id>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
             <configuration>
                    <!-- Sets the path to the file which contains the execution data. -->
                    <destFile>${basedir}/target/jacoco.exec</destFile>
                    <!--
                        Sets the name of the property containing the settings
                        for JaCoCo runtime agent.
                    -->
            </configuration>
        </execution>
        <execution>
            <!--<id>post-unit-test</id>
            <phase>test</phase>-->
            <id>default-report</id>
            <phase>verify</phase>
            <goals>
                <goal>report</goal>
            </goals>
              <configuration>
                <!-- Sets the path to the file which contains the execution data. -->
                <dataFile>${basedir}/target/jacoco.exec</dataFile>
                <!-- Sets the output directory for the code coverage report. -->
                <outputDirectory>${basedir}/target/jacoco-ut</outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>

Ниже приведена моя запись в pom.xml для maven-surefire-plugin

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
      <configuration>
            <argLine>@{argLine}</argLine>
            <skipTests>false</skipTests>
            <testFailureIgnore>true</testFailureIgnore>
        </configuration>
    </plugin>

@{argLine} был установлен как свойство

<properties>
    <argLine>-noverify -Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=512m</argLine>
</properties>

И обновил мою версию powermock с 1.5.5 до 1.6.5. Наконец, я мог видеть свое поколение отчетов для классов, в которых я использовал следующие теги в своих тестах @RunWith (PowerMockRunner.class) @PrepareForTest ({})

Ответ 5

В итоге я использовал автономную аппаратуру и Jacoco (аналогично тому, что вы сделали) в сочетании с sonar, и я смог получить номера покрытия из этого.

Ответ 6

Я использовал автономное инструментарий Jacoco и после выполнения теста восстановил исходные классы с помощью цели "restore-instrumented-classes". Моя конфигурация JaCoCo выглядит так:

 <plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.7.9</version>
    <executions>
      <execution>
        <id>default-prepare-agent</id>
        <goals>
          <goal>prepare-agent</goal>
        </goals>
      </execution>
      <execution>
        <id>jacoco-instrument</id>
        <goals>
          <goal>instrument</goal>
        </goals>
      </execution>
      <execution>
        <id>jacoco-restore-instrumented-classes</id>
        <goals>
          <goal>restore-instrumented-classes</goal>
        </goals>
      </execution>
      <execution>
        <id>jacoco-report</id>
        <phase>package</phase>
        <goals>
          <goal>report</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <excludes>
        <exclude>*</exclude>
      </excludes>
    </configuration>
  </plugin>

Ответ 7

У меня была такая же проблема с JaCoCo On-the-fly и PowerMock. Покрытие кода 0% генерируется каждый раз

Выяснилось, что JaCoCo версии 0.7.7.201606060606 и PowerMock версии 1.6.2 совместимы и покрытие кода сформировано успешно.

Ответ 8

Используйте приведенный ниже фрагмент кода подключаемого модуля maven, он отлично работает как в jenkins, так и в локальном режиме и показывает полное покрытие кода для модульных тестов PowermockRunner.

<build>
            <plugins>
                <plugin>
                    <groupId>org.jacoco</groupId>
                    <artifactId>jacoco-maven-plugin</artifactId>
                    <version>${jacoco-maven-plugin.version}</version>
                    <executions>
                        <execution>
                            <id>pre-test</id>
                            <goals>
                                <goal>prepare-agent</goal>
                            </goals>
                            <configuration>
                                <append>true</append>                           
                            </configuration>
                        </execution>
                        <execution>
                            <id>pre-integ-test</id>
                            <goals>
                                <goal>prepare-agent-integration</goal>
                            </goals>
                            <configuration>
                                <append>true</append>                           
                            </configuration>
                        </execution>

                        <execution>
                            <id>jacoco-instrument</id>
                            <goals>
                                <goal>instrument</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>jacoco-restore-instrumented-classes</id>
                            <goals>
                                <goal>restore-instrumented-classes</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <excludes>
                            <exclude>*</exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </build>

Ответ 9

Для меня этот образец автономного приборостроения работает хорошо.

Но в моем случае оказывается, что есть более простое решение: просто не включайте проверенный класс в аннотацию @PrepareForTest ({}) перед его объявлением.

Ответ 10

Покрытие кода с помощью JaCoCo объяснило причину

Самый простой способ использовать JaCoCo - это инструментарий на лету с использованием Java-агента JaCoCo. В этом случае класс изменяется при загрузке. Вы можете просто запустить свое приложение с агентом JaCoCo и рассчитать покрытие кода. Этот способ используется Eclemma и Intellij Idea. Но есть большая проблема. Классы инструментов PowerMock также. Javassist используется для изменения классов. Основная проблема заключается в том, что Javassist читает классы с диска, и все изменения JaCoCo исчезают. В результате нулевое покрытие кода для классов, загружаемых загрузчиком классов PowerMock.

Мы собираемся заменить Javassist на ByteBuddy (# 727), и это должно помочь решить эту старую проблему. Но сейчас НЕТ СПОСОБА ИСПОЛЬЗОВАНИЯ PowerMock с инструментами JaCoCo "на лету". И нет обходного пути для получения покрытия кода в IDE.

JaCoCo Offline Instrumentation может решить эту проблему. Пример автономного инструментария решил мою проблему.

Ответ 11

Отчет правильный. Приведенный тест не дает никакого покрытия, так как вы высмеиваете, что происходит при вызове метода "say". Никогда не надо издеваться над "тестируемым экземпляром/классом", делайте это только для зависимостей и окружения испытуемого.

В этом случае: код return "hello:"+s; тест никогда не достигается и конструктор Utils не вызывается. Покрытие не отображается, поскольку тестовое покрытие этих линий вообще отсутствует.

Тем не менее, совместное использование JaCoCo и PowerMock не является тривиальным. В настоящее время я тоже ищу, как заставить его работать. Может быть, ваш тест просто неудачно написан, а JaCoCo уже работает как надо?