【问题标题】:Missing jacoco.exec file when using jacoco offline instrumentation with Powermock使用带有 Powermock 的 jacoco 离线检测时缺少 jacoco.exec 文件
【发布时间】:2016-04-27 09:23:48
【问题描述】:

尽管post 显然展示了使用 powermock 和 jacoco 的解决方案,但我无法使其在一个非常简单的项目中工作 (available on GitHub)。

在我的情况下,测试正确执行,但缺少 jacoco.exec 文件,因此 jacoco 不检查覆盖率。

测试类:

@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\6-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\6-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\6-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\6-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\6-Workspaces\libertyGecon\jacoco-powermock\target\jacoco.exec
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ jacoco-powermock ---
[INFO] Building jar: C:\SoftDesarrollo\6-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\6-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 类覆盖率为 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

【问题讨论】:

    标签: maven powermock jacoco powermockito jacoco-maven-plugin


    【解决方案1】:
    <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 只是为了测试其他名为 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,并在一个单元测试中强制它返回正确的字符串,而在另一个测试中让它返回一个不正确的字符串。您不关心测试 User.class,您知道它会相应地运行,或者您将有另一个测试来处理它。对于 UtilUser 单元测试,您可以期望 Util 返回正确的字符串或不正确的字符串,并且您希望测试这两种可能性。

    模拟有时间和地点,它们是一个很好的了解工具,但不要认为它们应该经常使用。请参考以下文章,它将让您深入了解何时应该使用模拟:When To Mock

    【讨论】:

    • 感谢您的建议,我已经认为这可能是原因,甚至使用了绝对 URL。但是 jacoco.exec 文件仍然丢失...
    • @codependet 这是我会尝试的东西,它可能会给我更多的信息来帮助你。如果您使用的是 eclipse,请尝试在本地运行代码覆盖。告诉我这是否有效。我发现的一件事是默认仪器只需要在测试文件上运行。尝试将&lt;includes&gt; &lt;include&gt;**/*test*&lt;/include&gt; &lt;/includes&gt; 添加到您的默认仪器并恢复目标配置。 (如果您正在运行正常的准备代理,这也将有助于解决未来的问题)。
    • @codependent 我的项目在使用 JaCoCo 和 Powermock 时还需要一件事是 javassist,尝试将它也导入到您的 maven 文件依赖项中。
    • @codependent 繁荣!弄清楚为什么**/*test* 没有参加测试课程。错误的 powermock 版本。请忽略我之前的评论。将您的 powermock 版本更改为 1.6.4,您的代码覆盖率将显示出来 :)
    • 你就是那个男人!!非常感谢您花时间解决这个问题,谢谢!
    猜你喜欢
    • 2018-05-10
    • 2018-03-04
    • 2020-10-16
    • 1970-01-01
    • 2017-05-13
    • 1970-01-01
    • 2016-07-18
    • 2020-09-26
    • 1970-01-01
    相关资源
    最近更新 更多