• 代码覆盖率统计Super-jacoco在公司级容器化项目中的具体应用方案


    目录

    一、介绍

    二、自己在本地搭建Super-jacoco服务

    2.1 准备工作

    2.2 部署super jacoco服务

    1、下载super jacoco 项目

    2、初始化数据库

    3、配置application.properties

    4、编译super jacoco项目

    5、部署 super jacoco 服务

    2.3 启动被测项目

    2.4、代码覆盖率收集

    2.4.1 启动代码覆盖率收集

    2.4.2 获取代码覆盖率

    三、公司项目级docker容器化项目Super-jacoco应用

    3.1 镜像准备

    3.2 部署项目

    3.3 测试同学部署Super-jacoco服务

    3.3.1 、数据库准备,用于存储报告信息等。

    3.3.2 配置Super-jacoco服务application.properties信息

     3.3.3、编译super jacoco项目

    3.3.4、部署 super jacoco 服务

     3.4、代码覆盖率收集

    3.4.1 启动代码覆盖率收集

    3.4.2 获取代码覆盖率

    四、报错处理

    4.1 "errMsg": "统计失败:编译代码出错"

    4.2 编译失败 (权限相关)

    4.3 编译失败 (网络慢)

    4.4 编译失败 

    五、Super-jacoco原理

    5.1 整体流程

    5.2 获取增量代码

    5.3. jacoco 二次改造,支持增量方法列表参数

    5.4. 执行

    5.5. 报告输出

    5.6、架构

    六、相关资料:

    七、代码覆盖率收集 (使用说明)

    7.1 正常场景

    7.2 被测项目重启的场景

    7.3 被测项目(新增了代码)重启的场景

    八、报告解读:

    九、注意事项:


    一、介绍

    Super-jacoco 在jacoco 上发展而来,可以统计增量代码覆盖率的统计。

    jacoco 相关说明:jacoco代码覆盖率_jacoco覆盖率_做测试的喵酱的博客-CSDN博客

    本文介绍 Super-jacoco 统计手工用例代码覆盖率的统计数据。

    主要分两部分:

    一、自己在本地搭建Super-jacoco,自己玩一玩

    二、在公司的容器化项目中,如何使用Super-jacoco统计手工用例的代码覆盖率

     GitHub项目地址:

    GitHub - didi/super-jacoco

    GitHub - didi/super-jacoco

    尽量使用git命令,直接下载:

    git clone https://github.com/didi/super-jacoco.git
    

    二、自己在本地搭建Super-jacoco服务

    2.1 准备工作

    1. 准备gitlab用户
    2. 准备一个MySQL数据库5.x或者8.x版本

    2.2 部署super jacoco服务

    1、下载super jacoco 项目

    GitHub - didi/super-jacoco

    2、初始化数据库

    在super jacoco 项目中,sql/coverage_report.sql 文件用于初始化数据库。

    1. CREATE DATABASE `super-jacoco` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin ;
    2. CREATE TABLE `diff_coverage_report` (
    3. `id` int(10) NOT NULL AUTO_INCREMENT,
    4. `job_record_uuid` varchar(80) NOT NULL COMMENT '请求唯一标识码',
    5. `request_status` int(10) NOT NULL COMMENT '请求执行状态,1=下载代码成功,2=生成diffmethod成功,3=生成报告成功,-1=执行出错',
    6. `giturl` varchar(80) NOT NULL COMMENT 'git 地址',
    7. `now_version` varchar(80) NOT NULL COMMENT '本次提交的commidId',
    8. `base_version` varchar(80) NOT NULL COMMENT '比较的基准commitId',
    9. `diffmethod` mediumtext COMMENT '增量代码的diff方法集合',
    10. `type` int(11) NOT NULL DEFAULT '0' COMMENT '2=增量代码覆盖率,1=全量覆盖率',
    11. `report_url` varchar(300) NOT NULL DEFAULT '' COMMENT '覆盖率报告url',
    12. `line_coverage` double(5,2) NOT NULL DEFAULT '-1.00' COMMENT '行覆盖率',
    13. `branch_coverage` double(5,2) NOT NULL DEFAULT '-1.00' COMMENT '分支覆盖率',
    14. `err_msg` varchar(1000) NOT NULL DEFAULT '' COMMENT '错误信息',
    15. `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    16. `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
    17. `sub_module` varchar(255) NOT NULL DEFAULT '' COMMENT '子项目目录名称',
    18. `from` int(10) NOT NULL DEFAULT '0' COMMENT '1=单元测试,2=环境部署1=单元测试,2=hu',
    19. `now_local_path` varchar(500) NOT NULL DEFAULT '',
    20. `base_local_path` varchar(500) NOT NULL DEFAULT '',
    21. `log_file` varchar(255) NOT NULL DEFAULT '',
    22. PRIMARY KEY (`job_record_uuid`),
    23. KEY `id` (`id`)
    24. ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COMMENT='增量代码覆盖率';
    25. CREATE TABLE `diff_deploy_info` (
    26. `id` int(10) NOT NULL AUTO_INCREMENT,
    27. `job_record_uuid` varchar(80) NOT NULL COMMENT '请求唯一标识码',
    28. `address` varchar(15) NOT NULL COMMENT 'HOST',
    29. `port` int(10) NOT NULL COMMENT '端口',
    30. `code_path` varchar(1000) NOT NULL DEFAULT '' COMMENT 'nowVersion代码目录',
    31. `child_modules` varchar(1000) NOT NULL DEFAULT '' COMMENT '项目子模块名称',
    32. PRIMARY KEY (`job_record_uuid`),
    33. KEY `id` (`id`)
    34. ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COMMENT='服务部署地址';

    3、配置application.properties

    在下载下来的项目中,application.properties配置信息

    src/main/resources/application.properties

    1. # 以下信息需要手动配置
    2. spring.datasource.url=jdbc:mysql://127.0.0.1:3306/super-jacoco?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false
    3. spring.datasource.username=root
    4. spring.datasource.password=123456
    5. #git username & password
    6. gitlab.username=miaojiang
    7. gitlab.password=mj123456

    主要配置

    数据库的连接信息:url 账号 密码

    gitlab 的账号、密码

    注意:

    数据库的驱动配置,5.x与8.x 版本的MySQL,驱动是不一致的,根据自己的数据库配置。

     如果你的数据库为MySQL 8.x,需要修改项目中的驱动。

    1、修改pom.xml文件

    1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    3. <modelVersion>4.0.0</modelVersion>
    4. <groupId>com.didichuxing.chefuqa</groupId>
    5. <artifactId>super-jacoco</artifactId>
    6. <packaging>jar</packaging>
    7. <version>1.0-SNAPSHOT</version>
    8. <name>super-jacoco</name>
    9. <description>project for Spring cloud eureka client</description>
    10. <parent>
    11. <groupId>org.springframework.boot</groupId>
    12. <artifactId>spring-boot-starter-parent</artifactId>
    13. <version>2.0.2.RELEASE</version>
    14. <relativePath/> <!-- lookup parent from repository -->
    15. </parent>
    16. <properties>
    17. <entity.target.dir>src/main/java/</entity.target.dir>
    18. <dao.resources.dir>src/main/resources/</dao.resources.dir>
    19. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    20. <java.version>1.8</java.version>
    21. <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    22. <mybatis-spring-boot>1.2.0</mybatis-spring-boot>
    23. <mysql-connector>8.0.26</mysql-connector>
    24. <JAVA_HOME>/Library/Java/JavaVirtualMachines/jdk1.8.0_121.jdk/Contents/Home</JAVA_HOME>
    25. </properties>
    26. <dependencies>
    27. <dependency>
    28. <groupId>org.jodd</groupId>
    29. <artifactId>jodd-core</artifactId>
    30. <version>5.1.6</version>
    31. </dependency>
    32. <dependency>
    33. <groupId>dom4j</groupId>
    34. <artifactId>dom4j</artifactId>
    35. <version>1.6.1</version>
    36. </dependency>
    37. <dependency>
    38. <groupId>org.jacoco</groupId>
    39. <artifactId>org.jacoco.core</artifactId>
    40. <version>0.8.4</version>
    41. </dependency>
    42. <dependency>
    43. <groupId>org.ow2.asm</groupId>
    44. <artifactId>asm</artifactId>
    45. <version>7.1</version>
    46. </dependency>
    47. <dependency>
    48. <groupId>org.springframework.boot</groupId>
    49. <artifactId>spring-boot-starter</artifactId>
    50. </dependency>
    51. <dependency>
    52. <groupId>org.springframework.boot</groupId>
    53. <artifactId>spring-boot-starter-web</artifactId>
    54. </dependency>
    55. <dependency>
    56. <groupId>org.springframework.boot</groupId>
    57. <artifactId>spring-boot-devtools</artifactId>
    58. <optional>true</optional>
    59. </dependency>
    60. <dependency>
    61. <groupId>org.springframework</groupId>
    62. <artifactId>spring-context-support</artifactId>
    63. <version>5.1.4.RELEASE</version>
    64. </dependency>
    65. <dependency>
    66. <groupId>org.springframework.boot</groupId>
    67. <artifactId>spring-boot-starter-test</artifactId>
    68. <scope>test</scope>
    69. </dependency>
    70. <dependency>
    71. <groupId>org.mybatis.spring.boot</groupId>
    72. <artifactId>mybatis-spring-boot-starter</artifactId>
    73. <version>${mybatis-spring-boot}</version>
    74. </dependency>
    75. <dependency>
    76. <groupId>org.projectlombok</groupId>
    77. <artifactId>lombok</artifactId>
    78. <version>1.16.16</version>
    79. </dependency>
    80. <!-- MySQL 连接驱动依赖 -->
    81. <dependency>
    82. <groupId>mysql</groupId>
    83. <artifactId>mysql-connector-java</artifactId>
    84. <version>${mysql-connector}</version>
    85. </dependency>
    86. <dependency>
    87. <groupId>commons-lang</groupId>
    88. <artifactId>commons-lang</artifactId>
    89. <version>2.6</version>
    90. </dependency>
    91. <dependency>
    92. <groupId>org.apache.commons</groupId>
    93. <artifactId>commons-pool2</artifactId>
    94. <version>2.5.0</version>
    95. </dependency>
    96. <dependency>
    97. <groupId>org.codehaus.jackson</groupId>
    98. <artifactId>jackson-mapper-asl</artifactId>
    99. <version>1.9.13</version>
    100. </dependency>
    101. <dependency>
    102. <groupId>org.codehaus.jackson</groupId>
    103. <artifactId>jackson-core-asl</artifactId>
    104. <version>1.9.13</version>
    105. </dependency>
    106. <dependency>
    107. <groupId>com.google.guava</groupId>
    108. <artifactId>guava</artifactId>
    109. <version>15.0</version>
    110. </dependency>
    111. <dependency>
    112. <groupId>net.sf.json-lib</groupId>
    113. <artifactId>json-lib</artifactId>
    114. <version>2.4</version>
    115. <classifier>jdk15</classifier>
    116. </dependency>
    117. <dependency>
    118. <groupId>com.jayway.jsonpath</groupId>
    119. <artifactId>json-path</artifactId>
    120. <version>2.2.0</version>
    121. </dependency>
    122. <dependency>
    123. <groupId>org.sharegov</groupId>
    124. <artifactId>mjson</artifactId>
    125. <version>1.4.1</version>
    126. </dependency>
    127. <dependency>
    128. <groupId>joda-time</groupId>
    129. <artifactId>joda-time</artifactId>
    130. <version>2.3</version>
    131. </dependency>
    132. <!-- pinyin-->
    133. <dependency>
    134. <groupId>com.belerweb</groupId>
    135. <artifactId>pinyin4j</artifactId>
    136. <version>2.5.1</version>
    137. </dependency>
    138. <dependency>
    139. <groupId>org.jdom</groupId>
    140. <artifactId>jdom2</artifactId>
    141. <version>2.0.6</version>
    142. </dependency>
    143. <!-- ssh的依赖 -->
    144. <dependency>
    145. <groupId>ch.ethz.ganymed</groupId>
    146. <artifactId>ganymed-ssh2</artifactId>
    147. <version>build210</version>
    148. </dependency>
    149. <dependency>
    150. <groupId>org.tmatesoft.svnkit</groupId>
    151. <artifactId>svnkit</artifactId>
    152. <version>1.8.7</version>
    153. </dependency>
    154. <dependency>
    155. <groupId>org.apache.httpcomponents</groupId>
    156. <artifactId>httpclient</artifactId>
    157. <version>4.5.5</version>
    158. </dependency>
    159. <dependency>
    160. <groupId>org.apache.httpcomponents</groupId>
    161. <artifactId>httpmime</artifactId>
    162. <version>4.2.3</version>
    163. </dependency>
    164. <dependency>
    165. <groupId>io.rest-assured</groupId>
    166. <artifactId>rest-assured</artifactId>
    167. <version>3.1.1</version>
    168. </dependency>
    169. <dependency>
    170. <groupId>org.eclipse.jgit</groupId>
    171. <artifactId>org.eclipse.jgit</artifactId>
    172. <version>4.9.0.201710071750-r</version>
    173. </dependency>
    174. <dependency>
    175. <groupId>com.github.javaparser</groupId>
    176. <artifactId>javaparser-core</artifactId>
    177. <version>3.4.4</version>
    178. </dependency>
    179. <!-- Swagger2核心包 -->
    180. <dependency>
    181. <groupId>io.springfox</groupId>
    182. <artifactId>springfox-swagger2</artifactId>
    183. <version>2.7.0</version>
    184. </dependency>
    185. <dependency>
    186. <groupId>io.springfox</groupId>
    187. <artifactId>springfox-swagger-ui</artifactId>
    188. <version>2.7.0</version>
    189. </dependency>
    190. <dependency>
    191. <!-- jsoup HTML parser library @ http://jsoup.org/ -->
    192. <groupId>org.jsoup</groupId>
    193. <artifactId>jsoup</artifactId>
    194. <version>1.10.2</version>
    195. </dependency>
    196. <dependency>
    197. <groupId>tk.mybatis</groupId>
    198. <artifactId>mapper-spring-boot-starter</artifactId>
    199. <version>2.0.2</version>
    200. </dependency>
    201. </dependencies>
    202. <dependencyManagement>
    203. <dependencies>
    204. <dependency>
    205. <groupId>org.springframework.cloud</groupId>
    206. <artifactId>spring-cloud-dependencies</artifactId>
    207. <version>${spring-cloud.version}</version>
    208. <type>pom</type>
    209. <scope>import</scope>
    210. </dependency>
    211. </dependencies>
    212. </dependencyManagement>
    213. <build>
    214. <finalName>super-jacoco</finalName>
    215. <plugins>
    216. <plugin>
    217. <groupId>org.springframework.boot</groupId>
    218. <artifactId>spring-boot-maven-plugin</artifactId>
    219. </plugin>
    220. <plugin>
    221. <groupId>org.apache.maven.plugins</groupId>
    222. <artifactId>maven-compiler-plugin</artifactId>
    223. <configuration>
    224. <source>1.8</source>
    225. <target>1.8</target>
    226. <compilerArguments>
    227. <bootclasspath>${java.home}/lib/rt.jar:${java.home}/lib/jce.jar</bootclasspath>
    228. </compilerArguments>
    229. </configuration>
    230. </plugin>
    231. <plugin>
    232. <groupId>org.mybatis.generator</groupId>
    233. <artifactId>mybatis-generator-maven-plugin</artifactId>
    234. <version>1.3.7</version>
    235. <configuration>
    236. <verbose>true</verbose>
    237. <overwrite>true</overwrite>
    238. <configurationFile>
    239. ${basedir}/src/main/resources/tk-mybatis-autogen.xml
    240. </configurationFile>
    241. <!--允许移动生成的文件 -->
    242. <verbose>true</verbose>
    243. <overwrite>true</overwrite>
    244. </configuration>
    245. <dependencies>
    246. <dependency>
    247. <groupId>mysql</groupId>
    248. <artifactId>mysql-connector-java</artifactId>
    249. <version>8.0.26</version>
    250. </dependency>
    251. <dependency>
    252. <groupId>tk.mybatis</groupId>
    253. <artifactId>mapper</artifactId>
    254. <version>4.1.5</version>
    255. </dependency>
    256. </dependencies>
    257. </plugin>
    258. </plugins>
    259. </build>
    260. </project>

    2、application.properties修改数据库配置驱动

     下面这个是8.x MySQL的驱动

    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver


    4、编译super jacoco项目

    修改完super jacoco项目中的配置文件,就可以编译该项目了。生成super jacoco.jar

    5、部署 super jacoco 服务

     启动super-jacoco.jar 服务

    执行命令

    nohup java -jar super-jacoco.jar &

    默认端口为8899

    可以8899端口,程序是否启动成功

    lsof -i:8899

    注意:

    在部署 super jacoco 服务的机器上,一定要有以下环境:

    1、有mvn环境,如果没有的话,需要配置

    2、有git环境,并配置了能拉取被测项目的gitlab账号和密码。

    可以自己在这台机器上手动试一下,是否有权限

    git clone xxx.xxx.git

    相关资料:

    Mac下安装Maven&idea配置maven_做测试的喵酱的博客-CSDN博客

    mac&linux配置环境变量详解_vim ~/.zshrc-CSDN博客

    2.3 启动被测项目

    1、在super jacoco项目中,找到jacoco/org.jacoco.agent-0.8.5-runtime.jar 文件。

    将org.jacoco.agent-0.8.5-runtime.jar 文件,放在被测服务部署的项目上。

    如放置路径为/usr/local/org.jacoco.agent-0.8.5-runtime.jar

    被测项目为 mock-server.jar

    启动被测项目:

    nohup java -javaagent:/usr/local/org.jacoco.agent-0.8.5-runtime.jar=includes=*,output=tcpserver,port=18513,address=*,append=true -jar mock-server.jar > /dev/null 2>&1 &

    命令解释:

    • nohup:忽略挂起信号,允许命令在后台运行。

    • java:启动 Java 虚拟机。

    • -javaagent:/usr/local/org.jacoco.agent-0.8.5-runtime.jar=includes=*,output=tcpserver,port=18513,address=*,append=true:配置 JaCoCo 代码覆盖率工具代理,其中:

      • /usr/local/org.jacoco.agent-0.8.5-runtime.jar:指定 JaCoCo 代理 Jar 文件的路径。

      • includes=*:指定要包括在覆盖率报告中的类的匹配模式。此处将所有类都包括在内。

      • output=tcpserver:指定覆盖率信息的输出模式。此处使用 TCP 服务器模式。

      • port=18513:指定 TCP 服务器的端口号。

      • address=*:指定 TCP 服务器的地址。此处使用星号 * 表示接受所有来自任何地址的连接。

      • append=true:指定是否将新的覆盖率数据附加到现有数据文件中。此处附加新的数据以保留历史数据。

    • -jar mock-server.jar:指定要运行的 Jar 文件,即 MockServer 的可执行 Jar 文件。

    • > /dev/null:将标准输出重定向到 /dev/null,即不输出任何信息。

    • 2>&1:将标准错误输出重定向到标准输出。

    • &:将进程置于后台运行。

    注意:

    port=18513 端口,是在被测试的服务所在服务器上,18513端口上,启一个jacoco监听的服务,一定要保证部署被测项目的机器,放开了18513 端口,且我们有权限访问18513 端口。

    启动被测项目后,我们可以查看18513 端口的服务是否启动成功

    lsof -i:18513

    2.4、代码覆盖率收集

    假如:

    super jacoco 服务部署在了 123.123.123.123 这台服务上了

    被测项目mock-server 部署在了 456.456.456.456 机器上了

    2.4.1 启动代码覆盖率收集

    1)启动覆盖率收集URL:

    http://123.123.123.123 /cov/triggerEnvCov

    调用方法:POST参数(body方式传入):

    1. {
    2. "uuid": "uuid",
    3. "type": 1,
    4. "gitUrl": "git@git",
    5. "subModule": "",
    6. "baseVersion": "master",
    7. "nowVersion": "master",
    8. "address": "456.456.456.456",
    9. "port": "18513"
    10. }

    备注:

    IP和port为被测服务所在服务器的IP和端口

    uuid: 自定义的一个id,将来拉取覆盖率时,通过这个uuid来拉取

    gitUrl: 被测项目的gitlab地址

    返回:

    1. {
    2. "code": 200,
    3. "data": true,
    4. "msg": "msg"
    5. }

    2.4.2 获取代码覆盖率

    覆盖率结果URL:

    http://123.123.123.123/cov/getEnvCoverResult

    调用方法:

    GET

    参数:

    uuid(String)

    返回:

    1. {
    2. "code": 200,
    3. "data": {
    4. "coverStatus": 1,
    5. "errMsg": "msg",
    6. "lineCoverage": 100.0,
    7. "branchCoverage": 100.0,
    8. "logFile": "file content",
    9. "reportUrl": "http://"
    10. },
    11. "msg": "msg"
    12. }

    三、公司项目级docker容器化项目Super-jacoco应用

    前提:

    需要运维、网络、研发、测试同学的相互配合。

    但是整体流程,其实和上面是一致的。

    下载Super-jacoco 项目:

    git clone https://github.com/didi/super-jacoco.git

    然后取出Super-jacoco 项目 中的 jacoco/org.jacoco.agent-0.8.5-runtime.jar 文件,与sql/coverage_report.sql文件。

    3.1 镜像准备

    本部分公司,主要是由运维同学负责。

    举例:

    依然是部署mock-server服务。

    之前的流程:

    运维: 准备 Dockerfile文件---生成镜像

    部署被测项目:拉取镜像,拉取被测项目的代码,进行编译,生成jar包。在容器中启动该项目

    应用jacoco流程:

    运维: 先把jacoco agent 的jar包打 放到某一个公共服务器的位置,
    然后编写 Dockerfile文件,在里面写拉jacoco agent  jar包的命令。 最后再通过这个Dockerfile文件生成的image镜像

    部署被测项目:

    拉取镜像,拉取被测项目的代码,进行编译,生成jar包。在容器中启动该项目。需要配置JAVA_OPTS的环境变量,把java agent信息配置到变量里

     -javaagent:/usr/local/org.jacoco.agent-0.8.5-runtime.jar=includes=*,output=tcpserver,port=18513,address=*,append=true

     服务的启动命令是

    java $JAVA_OPTS -jar xxx.jar

    这样,就拼接成了完整的运行命令:

    java -javaagent:/usr/local/org.jacoco.agent-0.8.5-runtime.jar=includes=*,output=tcpserver,port=18513,address=*,append=true -jar mock-server.jar

    运维同学要注意:

    要放开18513 这个端口,如果要对该端口做代理的话:

    jacoco并非http/https,如果测试环境的k8s集群里面,访问形式为ingress+svc的形式,ingress配置域名,svc配置ClusterIP的模式。但是这个ingress只能代理http/https两种协议的请求。这种代理模式是不通的。需要把svc的ClusterIP改为了NodePort的模式,就可以直接通过公共节点+PORT进行访问了。

    3.2 部署项目

    负责部署项目的同学 测试/研发,在自己公司的部署平台上,选择上面创建好的镜像,配置部署项目的命令。

    3.3 测试同学部署Super-jacoco服务

    3.3.1 、数据库准备,用于存储报告信息等。

    安装MySQL。

    使用sql/coverage_report.sql 初始化MySQL信息

    3.3.2 配置Super-jacoco服务application.properties信息

    在下载下来的项目中,application.properties配置信息

    src/main/resources/application.properties

    1. # 以下信息需要手动配置
    2. spring.datasource.url=jdbc:mysql://127.0.0.1:3306/super-jacoco?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false
    3. spring.datasource.username=root
    4. spring.datasource.password=123456
    5. #git username & password
    6. gitlab.username=miaojiang
    7. gitlab.password=mj123456

    主要配置

    数据库的连接信息:url 账号 密码

    gitlab 的账号、密码

    注意:

    数据库的驱动配置,5.x与8.x 版本的MySQL,驱动是不一致的,根据自己的数据库配置。

     如果你的数据库为MySQL 8.x,需要修改项目中的驱动,具体修改方式在第二章有写,上面翻一番

     3.3.3、编译super jacoco项目

    修改完super jacoco项目中的配置文件,就可以编译该项目了。生成super jacoco.jar

    3.3.4、部署 super jacoco 服务

     启动super-jacoco.jar 服务

    执行命令

    nohup java -jar super-jacoco.jar &

    默认端口为8899

    可以8899端口,程序是否启动成功

    lsof -i:8899

    注意:

    在部署 super jacoco 服务的机器上,一定要有以下环境:

    1、有mvn环境,如果没有的话,需要配置

    2、有git环境,并配置了能拉取被测项目的gitlab账号和密码。

    可以自己在这台机器上手动试一下,是否有权限

    git clone xxx.xxx.git

    3、启动super jacoco 服务的机器,一定要有访问被测服务器18513端口的权限。

    公司中对服务器权限、端口权限控制的比较严,可能需要走工单进行申请,这个需要注意。

     3.4、代码覆盖率收集

    假如:

    super jacoco 服务部署在了 123.123.123.123 这台服务上了

    被测项目mock-server 部署在了 456.456.456.456 机器上了

    3.4.1 启动代码覆盖率收集

    1)启动覆盖率收集URL:

    http://123.123.123.123 /cov/triggerEnvCov

    调用方法:POST参数(body方式传入):

    1. {
    2. "uuid": "uuid",
    3. "type": 1,
    4. "gitUrl": "git@git",
    5. "subModule": "",
    6. "baseVersion": "master",
    7. "nowVersion": "master",
    8. "address": "456.456.456.456",
    9. "port": "18513"
    10. }

    备注:

    IP和port为被测服务所在服务器的IP和端口

    uuid: 自定义的一个id,将来拉取覆盖率时,通过这个uuid来拉取

    gitUrl: 被测项目的gitlab地址

    返回:

    1. {
    2. "code": 200,
    3. "data": true,
    4. "msg": "msg"
    5. }

    3.4.2 获取代码覆盖率

    覆盖率结果URL:

    http://123.123.123.123/cov/getEnvCoverResult

    调用方法:

    GET

    参数:

    uuid(String)

    返回:

    1. {
    2. "code": 200,
    3. "data": {
    4. "coverStatus": 1,
    5. "errMsg": "msg",
    6. "lineCoverage": 100.0,
    7. "branchCoverage": 100.0,
    8. "logFile": "file content",
    9. "reportUrl": "http://"
    10. },
    11. "msg": "msg"
    12. }

    四、报错处理

    4.1 "errMsg": "统计失败:编译代码出错"

    背景:

    拉取报告时 提示 ,统计失败:编译代码出错

    原因:

    查看启动super jacoco 服务的日志:

    1. 2023-10-12 17:01:14,642 INFO (CodeCloneExecutor.java:45)- uuid miaojiang开始下载代码...
    2. 2023-10-12 17:01:16,316 INFO (CodeCloneExecutor.java:52)- uuid miaojiang完成下载代码...
    3. 2023-10-12 17:01:16,322 DEBUG (BaseJdbcLogger.java:181)- ==> Preparing: UPDATE diff_coverage_report SET `request_status`=?, `err_msg`=?, `line_coverage`=?, `branch_coverage`=?, `report_url`=?, `diffmethod`=?, `log_file`=?, `now_local_path`=?, `update_time`=NOW() WHERE job_record_uuid=?
    4. 2023-10-12 17:01:16,323 DEBUG (BaseJdbcLogger.java:181)- ==> Parameters: 102(Integer), (String), -1.0(Double), -1.0(Double), (String), (String), http://127.0.0.1:8899/logs/miaojiang.log(String), /Users/zhaohui/app/super_jacoco/clonecode/miaojiang/master(String), miaojiang(String)
    5. 2023-10-12 17:01:16,327 DEBUG (BaseJdbcLogger.java:181)- <== Updates: 1
    6. 2023-10-12 17:01:16,328 DEBUG (BaseJdbcLogger.java:181)- ==> Preparing: UPDATE diff_coverage_report SET `request_status`=?, `err_msg`=?, `line_coverage`=?, `branch_coverage`=?, `report_url`=?, `diffmethod`=?, `log_file`=?, `now_local_path`=?, `update_time`=NOW() WHERE job_record_uuid=?
    7. 2023-10-12 17:01:16,329 DEBUG (BaseJdbcLogger.java:181)- ==> Parameters: 3(Integer), (String), -1.0(Double), -1.0(Double), (String), (String), http://127.0.0.1:8899/logs/miaojiang.log(String), /Users/zhaohui/app/super_jacoco/clonecode/miaojiang/master(String), miaojiang(String)
    8. 2023-10-12 17:01:16,331 DEBUG (BaseJdbcLogger.java:181)- <== Updates: 1
    9. IP:127.0.0.1
    10. 2023-10-12 17:01:16,335 INFO (CmdExecutor.java:43)- CmdThreadPool:java.util.concurrent.ThreadPoolExecutor@4b5dade5[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
    11. 2023-10-12 17:01:16,335 INFO (CmdExecutor.java:48)- executeCmd : bash -c cd /Users/zhaohui/app/super_jacoco/clonecode/miaojiang/master&&mvn clean compile >>/Users/zhaohui/report/logs/miaojiang.log
    12. 2023-10-12 17:01:16,346 INFO (CmdExecutor.java:101)- bash: mvn: command not found
    13. 2023-10-12 17:01:16,347 INFO (CmdExecutor.java:56)- readLine.stop();
    14. 2023-10-12 17:01:16,347 INFO (CmdExecutor.java:58)- progressBar.stop();
    15. 2023-10-12 17:01:16,348 INFO (CmdExecutor.java:59)- executeCmd done !!!!!!
    16. 2023-10-12 17:01:16,348 INFO (CmdExecutor.java:60)- worker done !!!!!! times = 0s
    17. 2023-10-12 17:01:16,349 DEBUG (BaseJdbcLogger.java:181)- ==> Preparing: UPDATE diff_coverage_report SET `request_status`=?, `err_msg`=?, `line_coverage`=?, `branch_coverage`=?, `report_url`=?, `diffmethod`=?, `log_file`=?, `now_local_path`=?, `update_time`=NOW() WHERE job_record_uuid=?
    18. 2023-10-12 17:01:16,350 DEBUG (BaseJdbcLogger.java:181)- ==> Parameters: 203(Integer), 编译代码出错(String), -1.0(Double), -1.0(Double), (String), (String), http://127.0.0.1:8899/logs/miaojiang.log(String), /Users/zhaohui/app/super_jacoco/clonecode/miaojiang/master(String), miaojiang(String)
    19. 2023-10-12 17:01:16,352 DEBUG (BaseJdbcLogger.java:181)- <== Updates: 1
    20. 2023-10-12 17:01:16,352 INFO (CodeCovServiceImpl.java:252)- Thread-4计算覆盖率具体步骤...编译失败uuid=miaojiang
    21. 2023-10-12 17:01:16,353 INFO (CodeCovServiceImpl.java:309)- Thread-4计算覆盖率具体步骤...编译失败uuid=miaojiang
    22. 2023-10-12 17:01:19,981 DEBUG (BaseJdbcLogger.java:181)- ==> Preparing: SELECT * from diff_coverage_report WHERE `request_status`=? AND `from`=? ORDER BY `update_time` asc limit ?
    23. 2023-10-12 17:01:19,987 DEBUG (BaseJdbcLogger.java:181)- ==> Parameters: 0(Integer), 1(Integer), 1(Integer)

    根据日志信息,可以看出发生了以下事件:

    17:01:14 - miaojiang开始下载代码。
    17:01:16 - miaojiang完成下载代码。
    17:01:16 - 执行数据库更新操作,更新了diff_coverage_report表的一行数据。
    17:01:16 - 执行数据库更新操作,再次更新了diff_coverage_report表的一行数据。
    17:01:16 - 从IP地址为127.0.0.1的主机上执行命令:cd /Users/zhaohui/app/super_jacoco/clonecode/miaojiang/master&&mvn clean compile >>/Users/zhaohui/report/logs/miaojiang.log,但是出现了错误:bash: mvn: command not found。
    17:01:16 - 终止读取日志和进度条。
    17:01:16 - 执行命令结束,执行时间为0秒。
    17:01:16 - 再次执行数据库更新操作,更新了diff_coverage_report表的一行数据,将request_status设为203,err_msg设为"编译代码出错"。
    17:01:16 - Thread-4处理计算覆盖率的具体步骤时发生编译失败,uuid为miaojiang。
    17:01:19 - 执行数据库查询操作,从diff_coverage_report表中选取request_status为0,from为1的记录,并按update_time升序排列,限制返回结果数量为1个。

    注意:

    bash: mvn: command not found。

    说明 127.0.0.1 服务上,没有配置mvn环境

    解决办法:

    在127.0.0.1 机器上,配置mvn环境

    4.2 编译失败 (权限相关)

    编译失败,还有一种可能是权限问题,在执行 mvn clean compile 时,可能需要拉取一些公司的内部资源,如果没有权限的话,依然会编译失败

    4.3 编译失败 (网络慢)

    编译过程中,在官方仓库拉取mvn资源时(repo.maven.apache.org),网络原因,下载速度非常慢,导致编译失败。

    我们可以给mvn settings.xml 配置一个国内的镜像,加速一下。

    找到mvn地址

    echo $M2_HOME

    找到这个路径下的/conf/settings.xml 文件。

    在 Maven 的 settings.xml 文件中可以设置镜像站点,在 标签中添加一个新的镜像即可。例如:

    1. <mirrors>
    2. <mirror>
    3. <id>alimaven</id>
    4. <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    5. <mirrorOf>*</mirrorOf>
    6. </mirror>
    7. </mirrors>

    4.4 编译失败 

    报错:

    2023-10-19 10:32:12,387 INFO (CmdExecutor.java:48)- executeCmd : bash -c cd /root/app/super_jacoco/clonecode/101901/master&&java -jar /root/org.jacoco.cli-1.0.2-SNAPSHOT-nodeps.jar dump --address 10.110.10.100 --port 18513 --destfile ./jacoco.exec 2023-10-19 10:32:12,393 INFO (CmdExecutor.java:101)- Error: Unable to access jarfile /root/org.jacoco.cli-1.0.2-SNAPSHOT-nodeps.jar

    解决办法:

    手动将super jacoco 项目中jacoco/org.jacoco.cli-1.0.2-SNAPSHOT-nodeps.jar 文件,复制到服务器的/root目录下

    五、Super-jacoco原理

    5.1 整体流程

    为了支持增量覆盖率收集,我们需要做两件事情:**1)**获取不同版本代码diff文件;**2)**对jacoco进行二次开发,使其支持增量方法列表参数。

    5.2 获取增量代码

    主要流程:拉取master(参照分支)和feature(提测分支)代码,再通过JGit对两个分支源码进行比对,获取增量代码。以下为部分代码片段:

    5.3. jacoco 二次改造,支持增量方法列表参数

    JaCoCo 对 exec 的解析主要是在 Analyzer 类的 analyzeClass(final byte[] source) 方法。这里面会调用 createAnalyzingVisitor 方法,生成一个用于解析的 ASM 类访问器,继续跟代码,发现对方法级别的探针计算逻辑是在 ClassProbesAdapter 类的 visitMethod 方法里面。所以我们只需要改造 visitMethod 方法,使它只对提取出的每个类的新增或变更方法做解析,非指定类和方法不做处理。改造后的核心代码片段如下:

    5.4. 执行

    只需要在执行的mvn命令中加入-Djacoco.diffFile=变更方法列表,即可收集变更方法的代码覆盖率。如果不传入-Djacoco.diffFile或者Djacoco.diffFile参数为空,则默认收集全量覆盖率。

    5.5. 报告输出

    覆盖率报告如下图,在图中是某个 service 的实现类,在最新的代码中有23个方法,但是只会对变更或新增的5个方法进行覆盖率统计与显示:

    5.6、架构

    底层架构

    六、相关资料:

     滴滴开源Super-jacoco:java代码覆盖率收集平台 - 掘金

    七、代码覆盖率收集 (使用说明)

    在super jacoco的基础上,进行了二次开发,集成到了测试平台。

    这里简单说一下使用方法:

    数据是5分钟自动拉取一次,如果已经创建过任务,不需要再次创建任务。

    项目重启之前,创建一个任务。重启项目后,再创建新的任务:

    旧的任务会合并新的数据。新的任务并不会合并之前的报告。

    7.1 正常场景

    整体顺序是:

    1、先启动被测应用

    2、执行手工测试

    3、创建任务1(接口:/cov/triggerEnvCov)

    4、拉取报告(接口:/cov/getEnvCoverResult?uuid=任务1)

    5、执行的手工测试被成功收集

    注意:

    先执行手动测试,还是先创建任务,先后是没有顺序的,都可以的。

    7.2 被测项目重启的场景

    1、项目启动

    2、创建任务001(接口:/cov/triggerEnvCov)

    3、执行手工测试(A模块)

    4、重启被测项目

    5、创建任务002

    6、执行手工测试(B模块)

    查看数据(最好等5分钟之后,因为数据5分钟自动拉取一次)

    任务001:包含A模块与B模块的数据

    任务002:只包含B模块的数据

    7.3 被测项目(新增了代码)重启的场景

    1、项目启动

    2、创建任务001(接口:/cov/triggerEnvCov)

    3、执行手工测试(A模块)

    4、重启被测项目,并新增了C模块的代码

    5、创建任务002

    6、执行手工测试(B模块与C模块的数据)

    查看数据(最好等5分钟之后,因为数据5分钟自动拉取一次)

    任务001:包含A模块与B模块的数据

    任务002:包含B模块与C模块的数据

    7.4 增量代码覆盖

    研发在master上拉了一个dev分支。在dev分支上开发了一些新的功能。

    我只想要统计dev分支上新增的代码覆盖率,而不是dev分支所有的代码覆盖率。

    创建任务:

    1. {
    2. "uuid": "test_new_develop",
    3. "type": 2,
    4. "gitUrl": "http://xxxx.git",
    5. "subModule": "",
    6. "baseVersion": "master",
    7. "nowVersion": "develop",
    8. "address": "127.0.0.1",
    9. "port": "18513"
    10. }

    type:2 代表统计增量代码覆盖率

    baseVersion:master  最原始的分支,用来被比较的

    "nowVersion": "develop" 研发新增代码的分支

    八、报告解读:

    条件覆盖

    红钻:表示未覆盖

    黄钻:表示部分覆盖

    绿钻:表示全部覆盖

    注:条件覆盖都是用钻表示。

    Lines覆盖

    红色背景:无覆盖,该行的所有指令均无执行。

    背景:部分覆盖,该行部分指令被执行。

    绿色背景:全覆盖,该行所有指令被执行。

    九、注意事项:

    9.1 被测项目启动命令:

    nohup java -javaagent:/usr/web/cs_super_jacoco/org.jacoco.agent-0.8.5-runtime.jar=includes=*,output=tcpserver,port=18513,address=,append=true -jar com_ky.jar > /dev/null 2>&1 &
    

    注意:

    includes=* ,这里一定要使用星号哦,不要忘了

  • 相关阅读:
    python学习笔记之word文档提取
    网络安全(黑客)自学
    做了一份前端面试复习计划,保熟~
    【PTA-训练day6】L2-016 愿天下有情人都是失散多年的兄妹+ L1-011 帅到没朋友
    Nginx+cpolar实现内网穿透多个Windows Web站点端口
    如何快速下载mysql的不同版本并启动mysql服务?
    【实践篇MySQL执行计划详解
    ChatGPT全球最大开源平替OpenAssistant:基于Pythia和LLaMA微调而来
    ​iOS上架App Store的全攻略
    .NET周报【10月第2期 2022-10-17】
  • 原文地址:https://blog.csdn.net/qq_39208536/article/details/133906588