利用evosuite+jacoco自动生成单元测试代码并提供覆盖率报告
evosuite
官网:https://www.evosuite.org/ github: https://github.com/EvoSuite EvoSuite是由Sheffield(谢菲尔德)等大学联合开发的一种开源工具,用于自动生成测试用例集,生成的测试用例均符合Junit的标准,可直接在Junit中运行。 通过使用此自动测试工具能够在保证代码覆盖率的前提下极大地提高测试人员的开发效率。但是只能辅助测试,并不能完全取代人工,测试用例的正确与否还需人工判断。 官网有多种依赖方式:jar包、maven插件、idea插件、eclipse插件、docker镜像
jacoco
JaCoCo 是一个非常常用的计算代码覆盖率的工具. 达到的效果就是可以分析出在代码启动到某个时间点那些代码是执行过的, 哪些代码是从没执行的, 从而了解到代码测试的覆盖程度.
支持类级别, 方法级别, 行级别的覆盖率统计. 同时也支持分支级别的统计.
pom.xml文件中配置相关依赖:
依赖:
<junit.version>4.12</junit.version>
<!--自动化 junit 工具 Evosuite-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.evosuite</groupId>
<artifactId>evosuite-standalone-runtime</artifactId>
<version>1.0.6</version>
<scope>test</scope>
</dependency>
<!--自动化 junit 工具 Evosuite-->
配置插件仓库(可选):
<pluginRepositories>
<pluginRepository>
<id>EvoSuite</id>
<name>EvoSuite Repository</name>
<url>http://www.evosuite.org/m2/</url>
</pluginRepository>
</pluginRepositories>
build中的maven插件配置:
<!--自动化 junit 工具 Evosuite-->
<plugin>
<groupId>org.evosuite.plugins</groupId>
<artifactId>evosuite-maven-plugin</artifactId>
<version>1.0.6</version>
<configuration>
<!-- 离线模式,需要手动执行生成的单元测试需要删除这行 -->
<extraArgs> -Duse_separate_classloader=false </extraArgs>
</configuration>
</plugin>
<!--自动化 junit 工具 Evosuite-->
<!--使用离线模式jacoco生成覆盖率报告-->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.0</version>
<configuration>
<!-- Sets the path to the file which contains the execution data. -->
<dataFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</dataFile>
<destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile>
<!-- Sets the output directory for the code coverage report. -->
<outputDirectory>${project.reporting.outputDirectory}/jacoco-ut</outputDirectory>
</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>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.1</version>
<configuration>
<systemPropertyVariables>
<jacoco-agent.destfile>${project.build.directory}/coverage-reports/jacoco-ut.exec</jacoco-agent.destfile>
</systemPropertyVariables>
</configuration>
</plugin>
<!--使用离线模式jacoco生成覆盖率报告-->
执行命令生成单元测试代码:
Evosuite 是基于编译后的字节码来生成单测代码的,因此源代码必须先进行编译,然后才能使用evosuite.
mvn compile -DmemoryInMB=4000 -Dcores=4 -DtargetFolder=src/test/java evosuite:generate evosuite:export
// 常用参数
// -DmemoryInMB 使用4000MB内存执行
// -Duse_separate_classloader=false 离线模式(不使用evoRunner做)会调用EvoSuite自己的classloader
// -Dcores 4核处理
// -Dcuts="需要生产单元测试的类"
// 例如:-Dcuts="com.lishicloud.aImpl,com.lishicloud.bImpl"
// -Duse_separate_classloader=false 指定为离线模式
// 常用命令
// prepare:需要同时运行EvoSuite测试和现有测试mvn evosuite:prepare test
// evosuite:generate 表示执行生成用例
// evosuite:export 表示导出用例到 targetFolder 的值所在的目录中(默认值为“ src / test / java”)
// evosuite:clean:删除“ .evosuite”文件夹中的所有数据,该文件夹用于存储到目前为止生成的所有最佳测试
执行命令打包并跳过测试:
mvn clean -U -Dmaven.test.skip=true package
执行命令运行单元测试并生成报告:
启动Java程序时,使用java-agent参数指定JaCoCo代理程序。JVM启动时,会同时启动JaCoCo代理程序。当JVM通过Class Loader装载Class时,JaCoCo代理端会将统计代码(桩)实时插入Class,并在测试代码执行过程中统计分析覆盖率。
mvn test jacoco:restore-instrumented-classes jacoco:report
<!--
需要注意的是
1. maven-surefire-plugin 对应的plugin不可配置多个
2. 需要去除pom中plugin配置了跳过测试代码,如下加粗的代码
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.15</version>
<configuration>
<!-- 需要去除 -->
**<skip>true</skip>**
<systemPropertyVariables>
<jacoco-agent.destfile>${project.build.directory}/coverage-reports/jacoco-ut.exec</jacoco-agent.destfile>
</systemPropertyVariables>
</configuration>
</plugin>
检查是否生成报告:
对应目录
${项目path}/target/site/jacoco-ut/index.html 单模块可视化报告
${项目path}/target/site/jacoco-ut/jacoco.xml 单模块报告(最后推送给sonar)
执行命令将报告推送至sonar:
mvn sonar:sonar -Dsonar.coverage.jacoco.xmlReportPaths=/Users/xxx/snoar-evosuite/target/site/jacoco-ut/jacoco.xml -Dsonar.projectKey=snoar-evosuite -Dsonar.host.url=http://xxxx:9000 -Dsonar.login=xxx -Dsonar.projectName=sonar显示的项目名称 -Dsonar.java.coveragePlugin=jacoco
// 常用参数
// -Dsonar.coverage.jacoco.xmlReportPaths={path}
// path为项目target 下生成的报告路径 target下固定为:/site/jacoco-ut/jacoco.xml
// -Dsonar.projectKey、-Dsonar.host.url、-Dsonar.login 为sonar项目配置信息
// -Dsonar.java.coveragePlugin 指定sonar覆盖率报告采用jacoco方式
Evosuite 会自动对 service 依赖的其他对象进行 mock。
针对被测方法的参数,根据参数类型会使用各种边界值进行测试。
工具存在的不足之处: Mock 对象的方法调用只能返回空值 null 等,因此正常的逻辑无法走到。EvoSuite 生成的单测用例更适用于测试边界情况和异常情况。正常场景还是得靠人。
此方案可能出现覆盖率为0、多模块无法整合推送报告的情况,多模块和覆盖率问题参考:https://www.jianshu.com/p/4c2af38bc85f