JaCoCo增量覆盖率的基本实现原理

本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 什么是增量覆盖率 如图所示,在master分支提交了HelloController,然后从master拉了个新分支test;提交了第1次代码,增加了WorldController;提交了第2次代码,增加了DonController。增量的获取方式有两种: 版本对比:在分支上,第2次提交和第1次提交版本对比的增量代码,就是DonController;第2次提交和刚从master拉取分支时版本对比的增量代码,除了DonController还有WorldController; 分支对比:把test分支和master分支进行对比,增量代码就是DonController和WorldController; 增量,就是通过版本对比或分支对比,多出来的新增加的那部分代码。覆盖率是指程序运行以后,有多少代码被执行到了,除以总的代码数算出来的,即覆盖率=执行代码行数/总代码行数。增量覆盖率是针对增量代码来计算的,也就是增量覆盖率=执行代码行数/增量代码行数。 基本实现原理 使用JaCoCo的On-the-fly模式,以tcpserver方式启动,将远程机器的覆盖率数据通过TCP通信dump到本地jacoco.exec文件,二次开发JaCoCo源码,实现增量覆盖率分析和输出HTML报告。 JaCoCo默认覆盖率 JaCoCo是一个开源的覆盖率工具,它的On-the-fly模式,无须侵入应用启动脚本,只需在JVM中通过-javaagent参数指定jar文件启动的代理程序,代理程序在ClassLoader装载一个class前判断是否需要注入class文件,将统计代码插入class,覆盖率分析就可以在JVM执行的过程中完成。 启动脚本示例: java -javaagent:jacocoagent.jar -jar target/app.jar 默认情况下,JaCoCo会在JVM停掉以后,生成覆盖率数据,一个jacoco.exec文件。 官方手册也有相关说明: output默认为file:At VM termination execution data is written to the file specified in the destfile attribute。这种方式有2个局限,一是必须停掉应用;二是只能把覆盖率数据生成到本地文件。 output还有另外一个选项,tcpserver: java -javaagent:jacocoagent.jar=output=tcpserver,address=0.0.0.0,port=2014 -jar target/app.jar address:服务端地址; port:服务端端口; 通过这种方式启动后,会同时启动一个TCP服务端,使用lsof -i :2014命令查看端口进程: 然后就能通过TCP通信,来获取覆盖率数据,也就是所谓的”dump“。 代码片段: @Override public void dump(String dumpPath, String ip, int port) throws IOException { dumpPath = FileUtil.getAbsolutePath(dumpPath); if (!FileUtil.exist(dumpPath)) { FileUtil.mkdir(dumpPath); } FileOutputStream localFile = new FileOutputStream(dumpPath + File.separator + "jacoco.exec"); ExecutionDataWriter localWriter = new ExecutionDataWriter(localFile); SocketAddress socketAddress = new InetSocketAddress(ip, port); Socket socket = new Socket(); try { socket.connect(socketAddress, 10000); RemoteControlWriter writer = new RemoteControlWriter(socket.getOutputStream()); RemoteControlReader reader = new RemoteControlReader(socket.getInputStream()); reader.setSessionInfoVisitor(localWriter); reader.setExecutionDataVisitor(localWriter); log.info("开始dump:{} {}", ip, port); writer.visitDumpCommand(true, false); if (!reader.read()) { log.error("Socket closed unexpectedly"); throw new IOException("Socket closed unexpectedly."); } log.info("dump完成:{} {}", ip, port); } catch (Exception e) { log.info("dump失败:{}", e.getMessage()); } finally { socket.close(); localFile.close(); } } dump经过TCP通信,将远程机器的覆盖率数据取到本地后,生成jacoco.exec文件,然后可以使用jacococli.jar生成HTML报告: ...

SpringBoot接入JaCoCo实践教程

本书作者:测试开发刚哥,文章版权归个人所有,未经授权请勿转载。 静态接入和动态接入 SpingBoot可以通过2种方式接入JaCoCo:Maven和Agent。Maven方式是静态接入,在编译时计算代码覆盖率。Agent方式是动态接入,服务启起来以后,能实时根据代码命中情况计算代码覆盖率。 教程代码已上传开源项目:https://github.com/dongfanger/mini Maven pom.xml添加依赖: <dependency> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.7</version> </dependency> 添加配置: <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${project.parent.version}</version> </plugin> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.7</version> <executions> <execution> <id>default-prepare-agent</id> <goals> <goal>prepare-agent</goal> </goals> </execution> <execution> <id>default-report</id> <goals> <goal>report</goal> </goals> </execution> </executions> </plugin> </plugins> </build> 点击maven的install: target/site/jacoco目录下就生成了覆盖率报告: Agent 下载jacoco文件后解压,提取2个文件: 使用命令启动SpringBoot,启动参数添加-javaagent: java -javaagent:jacoco/jacocoagent.jar -jar target/mini-0.0.1-SNAPSHOT.jar 此时会生成1个jacoco.exec文件,这个文件就是覆盖率数据文件,采用以下命令根据数据文件生成HTML报告: java -jar jacoco/jacococli.jar report jacoco.exec --classfiles ./target/classes/ --sourcefiles ./src/main/java/ --html ./report 接下来就来验证动态特性。把report目录和jacoco.exec都删了,因为jacoco每次部署只能分析一次。把服务停掉后,重新启动。这一次不直接分析,而是先用postman调一下接口: 然后再分析一把: ...

代码覆盖率从0到100的入门实践

JaCoCo全称是Java Code Coverage,Java代码覆盖率,广泛运用于各种测试平台对Java代码的全量覆盖率和增量覆盖率进行统计,分析代码行差异,度量单元测试效果。Jacoco也是精准测试的技术实现手段之一。