将 jacoco 离线检测与 Powermock 一起使用时缺少 jacoco.exec 文件
Missing jacoco.exec file when using jacoco offline instrumentation with Powermock
尽管显然如此 post showed a solution to using powermock and jacoco, I haven't been able to make it work in a pretty simple project (available on GitHub).
在我的例子中,测试执行正确,但缺少 jacoco.exec 文件,因此 jacoco 不检查覆盖率。
测试class:
@RunWith(PowerMockRunner.class)
@PrepareOnlyThisForTest(Util.class)
@PowerMockIgnore("org.jacoco.agent.rt.*")
public class UtilTest {
@Test
public void testSay() throws Exception {
PowerMockito.mockStatic(Util.class);
Mockito.when(Util.say(Mockito.anyString())).thenReturn("hello:mandy");
Assert.assertEquals("hello:mandy", Util.say("sid"));
}
}
Util.java
public class Util {
private Util() {}
public static String say(String s) {
return "hello:"+s;
}
}
pom.xml
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.codependent.jacocopower</groupId>
<artifactId>jacoco-powermock</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<plugins>
<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>${jacoco.version}</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>
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>CLASS</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.50</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<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>
<properties>
<powermock.version>1.5.4</powermock.version>
<jacoco.version>0.7.4.201502262128</jacoco.version>
</properties>
</project>
Maven执行跟踪,抱怨没有找到jacoco.exec文件:
>> mvn clean verify
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building jacoco-powermock 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ jacoco-powermock ---
[INFO] Deleting C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ jacoco-powermock ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ jacoco-powermock ---
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target\classes
[INFO]
[INFO] --- jacoco-maven-plugin:0.7.4.201502262128:instrument (default-instrument) @ jacoco-powermock ---
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ jacoco-powermock ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ jacoco-powermock ---
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.18.1:test (default-test) @ jacoco-powermock ---
[INFO] Surefire report directory: C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target\surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.codependent.jacoco.UtilTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.239 sec - in com.codependent.jacoco.UtilTest
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- jacoco-maven-plugin:0.7.4.201502262128:restore-instrumented-classes (default-restore-instrumented-classes) @ jacoco-powermock ---
[INFO]
[INFO] --- jacoco-maven-plugin:0.7.4.201502262128:report (default-report) @ jacoco-powermock ---
[INFO] Skipping JaCoCo execution due to missing execution data file:C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target\jacoco.exec
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ jacoco-powermock ---
[INFO] Building jar: C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target\jacoco-powermock-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- jacoco-maven-plugin:0.7.4.201502262128:check (default-check) @ jacoco-powermock ---
[INFO] Skipping JaCoCo execution due to missing execution data file:C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target\jacoco.exec
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.987s
[INFO] Finished at: Thu Jan 21 09:13:55 CET 2016
[INFO] Final Memory: 23M/331M
[INFO] ------------------------------------------------------------------------
更新:(here on GitHub)
根据 Lencalot 提供的答案,生成了 jacoco.exec 文件,但以下情况一直表明 ServiceImpl class 覆盖率为 0%:
ServiceImpl
public class ServiceImpl implements Service{
public String operation() {
return Util.say("Hi!");
}
}
服务测试
@RunWith(PowerMockRunner.class)
@PrepareForTest({Util.class})
public class ServiceTest {
private Service service = new ServiceImpl();
@Test
public void testOperation() throws Exception {
PowerMockito.mockStatic(Util.class);
Mockito.when(Util.say(Mockito.anyString())).thenReturn("Bye!");
Assert.assertEquals("Bye!", service.operation());
}
}
跟踪:
[WARNING] Rule violated for class com.codependent.jacoco.ServiceImpl: lines covered ratio is 0.00, but expected minimum is 0.50
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<configuration>
<append>true</append>
</configuration>
<executions>
<execution>
<id>default-instrument</id>
<goals>
<goal>instrument</goal>
</goals>
<configuration>
<includes>
<include>**/*test*</include>
</includes>
</configuration>
</execution>
<execution>
<id>default-restore-instrumented-classes</id>
<goals>
<goal>restore-instrumented-classes</goal>
</goals>
<configuration>
<includes>
<include>**/*test*</include>
</includes>
</configuration>
</execution>
<execution>
<id>Prepare-Jacoco</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<excludes>
<exclude>**/*test*</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
您现在可以删除 Check,我们可以先尝试让它正常工作。
将您的 Jacoco 依赖项更新为如下所示
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<version>${jacoco.version}</version>
<scope>test</scope>
</dependency>
让你的 maven surefire 插件看起来像这样:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>${argLine}</argLine>
</configuration>
</plugin>
在您的属性部分将此添加为,并更改您的 jacoco 版本:
<jacoco.version>0.7.5.201505241946</jacoco.version>
<jacoco.outputDir>${project.basedir}/target/jacoco.exec</jacoco.outputDir>
@codependent 这是一个你为什么要模拟的例子。
让我们假设您的 Util.class 有更多的代码,很多实例化,甚至可能触及一些服务器端的东西,甚至可能是 UI。您不想实例化 User.class 只是为了测试其他 class 中称为 UtilUser.class
的单个方法
protected class UtilUser {
protected UtilUser() {}
public Boolean checkSay(String s) {
String expectedString = "hello:" + s;
String actualString = Util.say(s);
if (expectedString.equals(actualString){
return true;
} else {
return false;
}
}
}
要对 UtilUser 进行单元测试,您需要访问所有分支。因此,在您的测试中,您将模拟 Util.class,并在一个单元测试中将其强制为 return 正确的字符串,而在另一项测试中,将其设为 return 不正确的字符串。您不关心测试 User.class,您知道它会相应地运行,否则您将有另一个测试来处理它。对于 UtilUser 的单元测试,您可以期望 Util return 一个正确的字符串或一个不正确的字符串,并且您想要测试这两种可能性。
模拟是有时间和地点的,它们是一个很好的了解工具,但不要认为它们应该经常使用。请参考以下文章,它会让您深入了解何时应该使用模拟:When To Mock
尽管显然如此 post showed a solution to using powermock and jacoco, I haven't been able to make it work in a pretty simple project (available on GitHub).
在我的例子中,测试执行正确,但缺少 jacoco.exec 文件,因此 jacoco 不检查覆盖率。
测试class:
@RunWith(PowerMockRunner.class)
@PrepareOnlyThisForTest(Util.class)
@PowerMockIgnore("org.jacoco.agent.rt.*")
public class UtilTest {
@Test
public void testSay() throws Exception {
PowerMockito.mockStatic(Util.class);
Mockito.when(Util.say(Mockito.anyString())).thenReturn("hello:mandy");
Assert.assertEquals("hello:mandy", Util.say("sid"));
}
}
Util.java
public class Util {
private Util() {}
public static String say(String s) {
return "hello:"+s;
}
}
pom.xml
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.codependent.jacocopower</groupId>
<artifactId>jacoco-powermock</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<plugins>
<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>${jacoco.version}</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>
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>CLASS</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>0.50</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<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>
<properties>
<powermock.version>1.5.4</powermock.version>
<jacoco.version>0.7.4.201502262128</jacoco.version>
</properties>
</project>
Maven执行跟踪,抱怨没有找到jacoco.exec文件:
>> mvn clean verify
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building jacoco-powermock 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ jacoco-powermock ---
[INFO] Deleting C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ jacoco-powermock ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ jacoco-powermock ---
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target\classes
[INFO]
[INFO] --- jacoco-maven-plugin:0.7.4.201502262128:instrument (default-instrument) @ jacoco-powermock ---
[INFO]
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ jacoco-powermock ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 0 resource
[INFO]
[INFO] --- maven-compiler-plugin:2.5.1:testCompile (default-testCompile) @ jacoco-powermock ---
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file to C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target\test-classes
[INFO]
[INFO] --- maven-surefire-plugin:2.18.1:test (default-test) @ jacoco-powermock ---
[INFO] Surefire report directory: C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target\surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.codependent.jacoco.UtilTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.239 sec - in com.codependent.jacoco.UtilTest
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- jacoco-maven-plugin:0.7.4.201502262128:restore-instrumented-classes (default-restore-instrumented-classes) @ jacoco-powermock ---
[INFO]
[INFO] --- jacoco-maven-plugin:0.7.4.201502262128:report (default-report) @ jacoco-powermock ---
[INFO] Skipping JaCoCo execution due to missing execution data file:C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target\jacoco.exec
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ jacoco-powermock ---
[INFO] Building jar: C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target\jacoco-powermock-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] --- jacoco-maven-plugin:0.7.4.201502262128:check (default-check) @ jacoco-powermock ---
[INFO] Skipping JaCoCo execution due to missing execution data file:C:\SoftDesarrollo-Workspaces\libertyGecon\jacoco-powermock\target\jacoco.exec
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.987s
[INFO] Finished at: Thu Jan 21 09:13:55 CET 2016
[INFO] Final Memory: 23M/331M
[INFO] ------------------------------------------------------------------------
更新:(here on GitHub)
根据 Lencalot 提供的答案,生成了 jacoco.exec 文件,但以下情况一直表明 ServiceImpl class 覆盖率为 0%:
ServiceImpl
public class ServiceImpl implements Service{
public String operation() {
return Util.say("Hi!");
}
}
服务测试
@RunWith(PowerMockRunner.class)
@PrepareForTest({Util.class})
public class ServiceTest {
private Service service = new ServiceImpl();
@Test
public void testOperation() throws Exception {
PowerMockito.mockStatic(Util.class);
Mockito.when(Util.say(Mockito.anyString())).thenReturn("Bye!");
Assert.assertEquals("Bye!", service.operation());
}
}
跟踪:
[WARNING] Rule violated for class com.codependent.jacoco.ServiceImpl: lines covered ratio is 0.00, but expected minimum is 0.50
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<configuration>
<append>true</append>
</configuration>
<executions>
<execution>
<id>default-instrument</id>
<goals>
<goal>instrument</goal>
</goals>
<configuration>
<includes>
<include>**/*test*</include>
</includes>
</configuration>
</execution>
<execution>
<id>default-restore-instrumented-classes</id>
<goals>
<goal>restore-instrumented-classes</goal>
</goals>
<configuration>
<includes>
<include>**/*test*</include>
</includes>
</configuration>
</execution>
<execution>
<id>Prepare-Jacoco</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<excludes>
<exclude>**/*test*</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
您现在可以删除 Check,我们可以先尝试让它正常工作。
将您的 Jacoco 依赖项更新为如下所示
<dependency>
<groupId>org.jacoco</groupId>
<artifactId>org.jacoco.agent</artifactId>
<version>${jacoco.version}</version>
<scope>test</scope>
</dependency>
让你的 maven surefire 插件看起来像这样:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>${argLine}</argLine>
</configuration>
</plugin>
在您的属性部分将此添加为,并更改您的 jacoco 版本:
<jacoco.version>0.7.5.201505241946</jacoco.version>
<jacoco.outputDir>${project.basedir}/target/jacoco.exec</jacoco.outputDir>
@codependent 这是一个你为什么要模拟的例子。
让我们假设您的 Util.class 有更多的代码,很多实例化,甚至可能触及一些服务器端的东西,甚至可能是 UI。您不想实例化 User.class 只是为了测试其他 class 中称为 UtilUser.class
的单个方法protected class UtilUser {
protected UtilUser() {}
public Boolean checkSay(String s) {
String expectedString = "hello:" + s;
String actualString = Util.say(s);
if (expectedString.equals(actualString){
return true;
} else {
return false;
}
}
}
要对 UtilUser 进行单元测试,您需要访问所有分支。因此,在您的测试中,您将模拟 Util.class,并在一个单元测试中将其强制为 return 正确的字符串,而在另一项测试中,将其设为 return 不正确的字符串。您不关心测试 User.class,您知道它会相应地运行,否则您将有另一个测试来处理它。对于 UtilUser 的单元测试,您可以期望 Util return 一个正确的字符串或一个不正确的字符串,并且您想要测试这两种可能性。
模拟是有时间和地点的,它们是一个很好的了解工具,但不要认为它们应该经常使用。请参考以下文章,它会让您深入了解何时应该使用模拟:When To Mock