maven - 在 Powermock 中使用 jacoco 离线检测时缺少 jacoco.exec 文件

标签 maven powermock jacoco powermockito jacoco-maven-plugin

尽管显然是这样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

最佳答案

<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,我们可以先尝试让它在没有 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

关于maven - 在 Powermock 中使用 jacoco 离线检测时缺少 jacoco.exec 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34918553/

相关文章:

eclipse - 从 Eclipse 中运行 Tomcat 总是给我 404(但 index.html 有效)

java - PowerMockito 私有(private) void 方法问题

java - 从jacoco和pit生成PDF文件

maven - maven 如何在构建 GWT 模块的依赖项构建时强制使用受支持的 GWT 源代码?

Eclipse Neon + JBossTools + Maven 结果出现错误 : No compiler is provided in this environment

java - Maven找不到本地安装的原型(prototype)

java - 使用任何 Java 模拟框架模拟聚合

java - 使用 powermock 测试返回服务的类?

gradle - 使用Gradle 5.X在Azure DevOps上生成代码覆盖率报告

scala - 如何合并来自多个子项目的 JaCoCo 报告