JaCOCO

  1. JaCoCo的ant与maven方法都是在编译期对单元测试的覆盖率统计
  2. JaCoCo的可以开启一个agent服务收集运行过程中的代码执行覆盖率。
    • 主要会用到jacoco 的两个功能:agentcli

覆盖率收集

收集方式

鉴于接口测试是在微服务启动后运行的测试,所以在选用第二种agent的测试,会有两个比较麻烦的地方(列出了自己比较笨拙的解决方法)

  1. 源码获取:去git上再拉取一遍。
  2. 编译后字节码获取:按照测试环境构建再统计过程中再构建一遍。

统计覆盖率过程基本如:

  1. 微服务启动,同时启动agent收集覆盖率
  2. 接下来基本都是jenkins任务需要做的
    • git获取项目源码
    • 使用构建工具编译源码
    • 使用cli工具获取JaCoCo覆盖率统计文件
    • 使用cli工具根据exec文件生成覆盖率报告

JaCoCo使用

官网下载jacoco-xxx.zip:https://www.jacoco.org/jacoco/

参考jacoco官方使用文档:官方文档索引agent帮助文档cli帮助文档

JaCoCo官方给出了3种收集覆盖率文件的方式

  • file
  • tcpserver
  • tcpclient。

在JVM虚拟机启动时加入参数:-javaagent:[yourpath/]jacocoagent.jar=[option1]=[value1],[option2]=[value2], 实例如下:

  1. 输出到文件,在JVM终止时,执行数据被写入本地文件。接口测试不会考虑这种情况(单元测试一般是用这种)

    1
    -javaagent:~/jacoco-0.8.5/lib/jacocoagent.jar=includes=*,output=file,append=true,destfile=~/jacoco-0.8.5/jacoco.exec
    • 服务终止影响整个测试环境。
    • 有些跨环境的服务,获取微服务所在机器上的文件也比较麻烦。
  2. 输出到tcpserver,使用工具连接到JVM,获取dump数据(可以实时的获取)。使用这种方式不需要停止jvm,也直接可以通过网络传输。但是远程连接没有任何身份验证机制,所以生产环境一定要确保只有信任的人可访问jacoco地址。配合jacoco cli获取数据。

    1
    -javaagent:~/jacoco-0.8.5/lib/jacocoagent.jar=includes=*,output=tcpserver,append=true,address=127.0.0.1,port=6301

    列出部分参数:

    • includes:插桩的代码类名列表,使用:分割,也可以使用*?匹配,但是不考虑性能的情况下一般不需要使用。默认为*
    • output:用于写入coverage数据的输出方法。有效选项包括:file、tcpserver、tcpclient、none
    • append:如果文件已经存在则追加到已存在文件中,如果为false则替换
    • destfile:输出exec文件的路径
    • address:配合tcpserver来指定对外开放的jacoco访问地址。如果配置的127.0.0.1或localhost则只能本地访问dump数据
    • port:配合tcpserver来指定对外开放的jacoco端口。端口不能被占用

JaCoCo命令行界面:命令行界面提供了基本的操作,基本能满足接口覆盖率报告的生成;dump数据与生成报告都使用cli。

  1. 获取jacoco server对外开放地址的数据。

    1
    java -jar ${jacoco_home}/lib/jacococli.jar dump --address ${address} --port ${port} --destfile ${destfile}
    • --address jacoco tcpserver地址,网络要通不然啥都白搭。
    • --port jacoco tcpserver端口
    • --destfile dump数据存储位置
  2. 使用获取到的exec文件生成覆盖率报告。

    1
    java -jar ${jacoco_home}/lib/jacococli.jar report ${destfile} --classfiles ${classfiles} --sourcefiles ${sourcefiles} --html reportdir
    • --classfiles 必须指定,源码编译后target目录文件。(这也是jenkins任务在单独拉取源码执行编译的原因)
    • --sourcefiles 源码,非必须项。不指定无法查看代码执行详细情况。
    • --html html报告生成目录

SpringBoot被测试项目

接口测试工程

本地测试手动获取集成测试覆盖率

  1. 使用jacocoagent本地启动SpringBoot被测试的项目

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    jingdeMacBook-Pro:jacoco-project apple$ ls
    jacoco-0.8.6 jacoco-0.8.6.zip spring-boot-restful-api-0.0.1-SNAPSHOT.jar
    jingdeMacBook-Pro:jacoco-project apple$ java -javaagent:./jacoco-0.8.6/lib/jacocoagent.jar -jar spring-boot-restful-api-0.0.1-SNAPSHOT.jar

    . ____ _ __ _ _
    /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    \\/ ___)| |_)| | | | | || (_| | ) ) ) )
    ' |____| .__|_| |_|_| |_\__, | / / / /
    =========|_|==============|___/=/_/_/_/
    :: Spring Boot :: (v2.3.4.RELEASE)

    2021-03-02 17:37:37.390 - WARN [] 14930 --- [ main] o.s.boot.StartupInfoLogger : InetAddress.getLocalHost().getHostName() took 5006 milliseconds to respond. Please verify your network configuration (macOS machines may need to add entries to /etc/hosts).
    2021-03-02 17:37:42.401 - INFO [] 14930 --- [ main] c.s.boot.demo.SpringBootDemoApplication : Starting SpringBootDemoApplication v0.0.1-SNAPSHOT on jingdeMacBook-Pro.local with PID 14930 (/Users/apple/JavaProject/jacoco-project/spring-boot-restful-api-0.0.1-SNAPSHOT.jar started by apple in /Users/apple/JavaProject/jacoco-project)
    2021-03-02 17:37:42.403 - INFO [] 14930 --- [ main] c.s.boot.demo.SpringBootDemoApplication : No active profile set, falling back to default profiles: default
    2021-03-02 17:37:45.055 - INFO [] 14930 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8988 (http)
    2021-03-02 17:37:45.092 - INFO [] 14930 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
    2021-03-02 17:37:45.093 - INFO [] 14930 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.38]
    ……

    我们看到项目已经启动成功了

  2. 执行接口自动化测试,等到测试执行完成,查看当前执行目录,会生成一个jacoco.exec文件

    1
    2
    3
    jingdeMacBook-Pro:jacoco-project apple$ ls
    jacoco-0.8.6 jacoco.exec
    jacoco-0.8.6.zip spring-boot-restful-api-0.0.1-SNAPSHOT.jar
  1. 使用jacococli命令生成jacoco测试报告

    1
    2
    3
    jingdeMacBook-Pro:jacoco-project apple$ java -jar jacoco-0.8.6/lib/jacococli.jar report jacoco.exec --classfiles=/Users/apple/JavaProject/spring-boot-restful-api/target/classes --sourcefiles=/Users/apple/JavaProject/spring-boot-restful-api/src/main/java --html report/ --xml report/jacoco.xml
    [INFO] Loading execution data file /Users/apple/JavaProject/jacoco-project/jacoco.exec.
    [INFO] Analyzing 17 classes.
  2. 进入到report目录下(该目录是提前创建好的),就可以查看jacoco生成的测试报告

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    jingdeMacBook-Pro:jacoco-project apple$ ls
    jacoco-0.8.6 jacoco.exec spring-boot-restful-api-0.0.1-SNAPSHOT.jar
    jacoco-0.8.6.zip report
    jingdeMacBook-Pro:jacoco-project apple$ cd report/
    jingdeMacBook-Pro:report apple$ ls
    com.spring.boot.demo com.spring.boot.demo.common.utils index.html
    com.spring.boot.demo.advance com.spring.boot.demo.controller jacoco-resources
    com.spring.boot.demo.common.config com.spring.boot.demo.entity jacoco-sessions.html
    com.spring.boot.demo.common.exception com.spring.boot.demo.filter jacoco.xml
    com.spring.boot.demo.common.response com.spring.boot.demo.service.impl
  3. 分别生成了html和xml的报告,打开index.html查看生成的html报告

    image-20210302182845741

  4. 这时已经完成了接口测试覆盖率的结果,下面我们也借助SonarQube具体进行代码分析,下面我们将结果通过sonar-scanner上传到SonarQube平台

    1
    2
    3
    4
    # 进入到工程目录下
    jingdeMacBook-Pro:jacoco-project apple$ cd /Users/apple/JavaProject/spring-boot-restful-api
    # 执行sonar-scanner命令进行测试结果上传
    jingdeMacBook-Pro:spring-boot-restful-api apple$ sonar-scanner -Dsonar.coverage.jacoco.xmlReportPaths=/Users/apple/JavaProject/jacoco-project/report/jacoco.xml -Dsonar.projectKey=spring-boot-restful-api-test -Dsonar.projectName=spring-boot-restful-api-test -Dsonar.language=java -Dsonar.sourceEncoding=UTF-8 -Dsonar.core.codeCoveragePlugin=jacoco -Dsonar.sources=./src/main/java -Dsonar.java.binaries=./target

    执行结果

    image-20210303135252621

    我们看到,执行成功,这时我们就可以到SonarQube平台,查看分析的结果了

    image-20210303135432139

本地测试开启监听模式实时的获取数据

  1. 使用jacocoagent监听模式本地启动SpringBoot被测试的项目

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    jingdeMacBook-Pro:jacoco-project apple$ java -javaagent:./jacoco-0.8.6/lib/jacocoagent.jar=includes=*,output=tcpserver,append=true,address=127.0.0.1,port=6301 -jar spring-boot-restful-api-0.0.1-SNAPSHOT.jar

    . ____ _ __ _ _
    /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
    \\/ ___)| |_)| | | | | || (_| | ) ) ) )
    ' |____| .__|_| |_|_| |_\__, | / / / /
    =========|_|==============|___/=/_/_/_/
    :: Spring Boot :: (v2.3.4.RELEASE)

    2021-03-03 16:19:02.674 - WARN [] 24535 --- [ main] o.s.boot.StartupInfoLogger : InetAddress.getLocalHost().getHostName() took 5002 milliseconds to respond. Please verify your network configuration (macOS machines may need to add entries to /etc/hosts).
    2021-03-03 16:19:07.686 - INFO [] 24535 --- [ main] c.s.boot.demo.SpringBootDemoApplication : Starting SpringBootDemoApplication v0.0.1-SNAPSHOT on jingdeMacBook-Pro.local with PID 24535 (/Users/apple/JavaProject/jacoco-project/spring-boot-restful-api-0.0.1-SNAPSHOT.jar started by apple in /Users/apple/JavaProject/jacoco-project)
    2021-03-03 16:19:07.687 - INFO [] 24535 --- [ main] c.s.boot.demo.SpringBootDemoApplication : No active profile set, falling back to default profiles: default
  2. 查看启动端口

    1
    2
    jingdeMacBook-Pro:jacoco-project apple$ netstat -p tcp -na | grep 6301
    tcp4 0 0 127.0.0.1.6301 *.* LISTEN
  3. 执行接口自动化测试,等到测试执行完成

  4. 使用jacococli命令监听并dump数据

    1
    2
    3
    4
    5
    6
    jingdeMacBook-Pro:jacoco-project apple$ java -jar jacoco-0.8.6/lib/jacococli.jar dump --address 127.0.0.1 --port 6301 --destfile jacoco_tcpserver.exec
    [INFO] Connecting to /127.0.0.1:6301.
    [INFO] Writing execution data to /Users/apple/JavaProject/jacoco-project/jacoco_tcpserver.exec.
    jingdeMacBook-Pro:jacoco-project apple$ ls
    Dockerfile jacoco-0.8.6.zip report
    jacoco-0.8.6 jacoco_tcpserver.exec spring-boot-restful-api-0.0.1-SNAPSHOT.jar

    这是我们看到新生成的结果文件jacoco_tcpserver.exec

  5. 使用jacococli命令生成jacoco测试报告

    1
    2
    3
    jingdeMacBook-Pro:jacoco-project apple$ java -jar jacoco-0.8.6/lib/jacococli.jar report jacoco_tcpserver.exec --classfiles=/Users/apple/JavaProject/spring-boot-restful-api/target/classes --sourcefiles=/Users/apple/JavaProject/spring-boot-restful-api/src/main/java --html report/ --xml report/jacoco.xml
    [INFO] Loading execution data file /Users/apple/JavaProject/jacoco-project/jacoco_tcpserver.exec.
    [INFO] Analyzing 17 classes.

    后续和“本地测试手动获取集成测试覆盖率”中的一致

Docker集成jacoco启动实例获取集成测试覆盖率

  1. 制作工程docker镜像,Dockerfile内容如下

    1
    2
    3
    4
    5
    6
    7
    8
    FROM java:8
    MAINTAINER jinglv
    ENV TZ "Asia/Shanghai"
    ENV LANG C.UTF-8
    VOLUME /tmp
    ADD spring-boot-restful-api-0.0.1-SNAPSHOT.jar restful.jar
    ENTRYPOINT ["java","-javaagent:/usr/local/jacocoagent.jar=includes=*,output=tcpserver,append=true,address=*,port=6301","-Djava.security.egd=file:/dev/./urandom","-jar","restful.jar"]
    EXPOSE 8988

    docker制作镜像命令:

    1
    jingdeMacBook-Pro:jacoco-project apple$ docker build -t restful_api .
  2. 启动docker镜像容器

    1
    docker run -d --name restful_api -p 8988:8988 -p 6301:6301 -v /Users/apple/JavaProject/jacoco-project/jacoco-0.8.6/lib/jacocoagent.jar:/usr/local/jacocoagent.jar restful_api
  3. 执行接口自动化测试,等到测试执行完成

  4. 使用jacococli命令监听并dump数据

    1
    2
    3
    4
    5
    6
    jingdeMacBook-Pro:jacoco-project apple$ java -jar jacoco-0.8.6/lib/jacococli.jar dump --address 127.0.0.1 --port 6301 --destfile jacoco_docker.exec
    [INFO] Connecting to /127.0.0.1:6301.
    [INFO] Writing execution data to /Users/apple/JavaProject/jacoco-project/jacoco_docker.exec.
    jingdeMacBook-Pro:jacoco-project apple$ ls
    Dockerfile jacoco-0.8.6.zip report
    jacoco-0.8.6 jacoco_docker.exec spring-boot-restful-api-0.0.1-SNAPSHOT.jar
  5. 通过jacococli命令生成jacoco测试报告,及查看测试报告

    1
    2
    3
    jingdeMacBook-Pro:jacoco-project apple$ java -jar jacoco-0.8.6/lib/jacococli.jar report jacoco_docker.exec --classfiles=/Users/apple/JavaProject/spring-boot-restful-api/target/classes --sourcefiles=/Users/apple/JavaProject/spring-boot-restful-api/src/main/java --html report/ --xml report/jacoco.xml
    [INFO] Loading execution data file /Users/apple/JavaProject/jacoco-project/jacoco_docker.exec.
    [INFO] Analyzing 17 classes.

    后续和“本地测试手动获取集成测试覆盖率”中的一致

已经完成JaCOCO接口测试的覆盖率收集,通过学习,接口测试的覆盖率是使用jacoco tcpserver模式进行收集,之后我们可以对Jenkins的工程进行改造,改进持续集成和持续交付。