我们项目中使用powerMock作为单元测试的mock工具,统计项目测试覆盖率使用jacoco编译的结果上传到sonar,但是jacoco 和 powerMock在运行时runtime加载代码的时候自定义了类加载器,所以就会有冲突,导致测试覆盖率为0。

使用命令 mvn clean verify sonar:sonar上传jacoco编译结果(这里sonar命令会自动调用jacoco-maven-plugin插件编译),出现错误:

[WARNING] Classes in bundle 'MyDemoProject' do not match with execution data. For report generation the same class files must be used as at runtime.
[WARNING] Execution data for class com/demo/controller/DemoController does not match.
 

 问题定位:运行时加载类出现问题

解决问题:

        找到jacoco 官方文档描述:https://www.eclemma.org/jacoco/trunk/doc/classids.html

        其中:

                

What happens if different classes are used at runtime and at analysis time?

In this case execution data cannot be related to the analyzed classes. As a consequence such classes are reported with 0% coverage.

What can cause different class ids?

Even if the class files on the file system are the same there is possible that classes seen by the JaCoCo runtime agent are different anyways. This typically happens when another Java agent is configured before the JaCoCo agent or special class loaders pre-process the class files. Typical candidates are:

  • Mocking frameworks
  • Application servers
  • Persistence frameworks

 上面清晰的描述了测试覆盖率为0的原因,和使用mock框架的影响。

解决方式参考:https://www.eclemma.org/jacoco/trunk/doc/examples/build/pom-offline.xml

最终pom 正确配置如下:

 <properties>
       <jacoco.version>0.8.8</jacoco.version>
 </properties>

<dependencies>

     <dependency>
             <!--  must be on the classpath  -->
            <groupId>org.jacoco</groupId>
            <artifactId>org.jacoco.agent</artifactId>
            <classifier>runtime</classifier>
            <version>${jacoco.version}</version>
            <scope>test</scope>
      </dependency>

 </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    
                    <systemPropertyVariables>
                        <jacoco-agent.destfile>${basedir}/../target/jacoco.exec</jacoco-agent.destfile>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>${jacoco.version}</version>

                <configuration>
                     <destFile>${basedir}/../target/jacoco.exec</destFile>
                    <dataFile>${basedir}/../target/jacoco.exec</dataFile>
                    <output>file</output>
                    <append>true</append>
                </configuration>
                <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>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

    <build>
  <plugins>

说明:

        上面的pom.xml是多模块项目中的父pom,其中jacoco.exec需要包含所有子模块的扫描结果,所以配置的路径是:${basedir}/../target/jacoco.exec(所有子模块的结果都是存放在父(根)目录下的target目录中),并且设置了 <append>true</append> 所有子模块生成一个jacoco.exec文件中。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐