「オンザフライ」でインストルメントするときにJacocoがPowerMockitoとうまく連携しないことを考えると、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"));
}
}
Javn.exeを生成するmvn clean installを実行します
カバレッジレポート(antスクリプトを使用してjacoco.execから生成):-
このポンは私のために働いた:
<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>
this リンクを参照してください。
私は同じ動作を見ましたが、GitHubの問題に関するスレッドをフォローした後、それは1.6.5で修正されたようで、それは私にとって真実であることが証明されました。
これが後で誰かの頭痛の種を救うことを願っています:)。
作業構成:
オフライン計測を使用していません。
PowerMockのjavaagentを使用して動作させました。ここを参照してください: 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>
私も同じ問題に直面していました。レポートを部分的に生成することができました。テストケースにこれらのタグを両方使用しました@RunWith(PowerMockRunner.class)@PrepareForTest({})。また、上記のタグを使用したテストケースのレポートは生成されませんでした。ただし、テストケースの1つでは、このタグは@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 for 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({})
私にとって、このサンプルの Offline Instrumentation はうまく機能します。
しかし、私の場合、簡単な解決策があることがわかります。テストするクラスを@PrepareForTest({})アノテーションに宣言の前に含めないでください。
sonar と組み合わせて、オフラインインスツルメンテーションとJacoco(あなたが行ったことに類似)を使用することになり、カバレッジ番号を取得することができました。
JaCoCo On-the-flyとPowerMockでも同じ問題がありました。毎回0%のコードカバレッジが生成されました
JaCoCoバージョン0.7.7.201606060606とPowerMockバージョン1.6.2は互換性があり、コードカバレッジが正常に生成されることがわかりました。
以下のMavenプラグインコードスニペットを使用します。これは、ジェンキンだけでなくローカルでも正常に機能し、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>
レポートは正しいです。メソッド「say」を呼び出したときに何が起こるかを模擬するため、提供されたテストではカバレッジが得られません。 「テスト対象のインスタンス/クラス」をモックすることは絶対にしないでください。テスト対象の依存関係と環境に対してのみモックを行ってください。
この場合:コードreturn "hello:"+s;
はテストによって到達されることはなく、Utilsのコンストラクターは呼び出されません。これらの回線のテストカバレッジがないため、カバレッジは表示されません。
それでも、JaCoCoとPowerMockを一緒に使用するのは簡単ではありません。現在、それを実行する方法も探しています。提供されたテストは不運にも書かれているだけで、JaCoCoはすでに正常に動作しているのでしょうか?
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>
JaCoCoのコードカバレッジ 理由の説明
JaCoCoを使用する最も簡単な方法は、JaCoCo Java Agentを使用したオンザフライのインスツルメンテーションです。この場合、ロード中にクラスが変更されます。 JaCoCoエージェントとコードカバレッジが計算されます。この方法はEclemmaとIntellij Ideaで使用されますが、大きな問題があります。PowerMockインストゥルメントクラスも使用します。 JaCoCoの変更はなくなり、その結果、PowerMockクラスローダーによってクラスwitchのコードカバレッジがゼロになります。
JavassistをByteBuddy(#727)に置き換えますが、この古い問題の解決に役立つはずです。しかし、現在、JaCoCo On-the-fly計装でPowerMockを使用する方法はありません。 IDEでコードカバレッジを取得するための回避策はありません。
JaCoCo Offline Instrumentationはこの問題を解決できます。 Offline Instrumentation のサンプルは私の問題を修正しました。