用JaCoCo工具看一下代码覆盖率,
一来看看测试有没有漏的测试用例
二来看看开发有没有留下冗余的代码
新开发项目Jacoco代码覆盖率
后端接口打成jar包,进行启动
----------------------
客户端:使用jacoco来生成覆盖率的文件、报告
----------------------
1.使用jacoco来生成覆盖率的文件:jacoco.exec
1. 获取到下载到的jacocoagent.jar
存放目录: /home/a/jacocoagent.jar 2. 要修改服务器配置---带上-javaagent选项。
【简单理解:javaagent类似于拦截器,在执行java的main方法之前,它会先执行javaagent里面的实现的premain方法】
修改java容器(jboss或者tomcat)启动jvm的选项:
* jboss:在文件/home/a/jboss-4.2.2.GA/bin/run.conf的最后添加下面的一行:
JAVA_OPTS="$JAVA_OPTS -javaagent:/home/a/jacocoagent.jar=destfile=/home/a/project/download/jacoco.exec" * tomcat:在目录下面/opt/taobao/tomcat/bin新建一个文件setenv.sh文件,内容如下:
export CATALINA_OPTS="-javaagent:/home/a/jacocoagent.jar=destfile=/home/a/project/download/jacoco.exec" 3.编译部署被测代码,启动服务器
最终查看ps -ef | grep java的时候,能够看到-javaagent选项。 4. 执行黑盒/集成/自动化测试。
它会生成覆盖率文件jacoco.exec,生成文件的路径就是在步骤#2中-javaagent中指定的(/home/a/project/output/jacoco.exec)。 5. 停止jboss/tomcat服务。
一定要停止jboss/tomcat服务,注意使用kill <pid>,不能使用kill -9 <pid>来杀死java进程,
原因是jacoco是在jboss/tomcat停止的时候,挂钩子来生成jacoco.exec文件的。kill -9是强制杀死进程,没法产生jacoco.exec文件的 6. 查看jacoco.exec文件是否已经生成以及更新时间是否为当前时间
ll /home/a/project/download/jacoco.exec 2.使用sonar来生成覆盖率的报告---处理jacoco.exec
1. 获取到被测工程的一份源代码,一般是从svn中check out出来。 2. 修改它的pom.xml文件,增加sonar插件
在pom.xml中的<build><plugins>....</plugins></build>中增加下面几行:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>2.0</version>
</plugin>
注意,该插件必须要求mvn3.0以上版本 3. 执行下面的命令来生成报告:
sudo mvn clean install -Ptest sonar:sonar -Dmaven.test.failure.ignore=true -Dsonar.jdbc.url=jdbc:h2:tcp://sonarip:9092/sonar -Dsonar.host.url=http://sonarip:9000 -Dsonar.jacoco.itReportPath="/home/a/project/download/jacoco.exec" -Dsonar.dynamicAnalysis 其中,
* sonar.jacoco.itReportPath:jacoco生成的覆盖率数据文件。
* sonar.jdbc.url:sonar使用的数据库链接地址(上文“安装sonar”中sonar被部署到的机器),如果sonar服务也是安装在这台机器上面,就可以省略。(默认值:jdbc:h2:tcp://localhost:9092/sonar)
* sonar.host.url:sonar服务的地址,同sonar.jdbc.url,如果sonar服务也是安装在这台机器上面,就可以省略。(默认值:http://localhost:9000) 4. So,如果一切顺利的话,你访问http://sonarip:9000,就能够看到集成测试的覆盖率数据了。Enjoy!
【如果在Dashboards上面找不到Integration tests coverage这个widget,可以在Dashboards上面添加的】
#execute
t1=$(date)
nohup /opt/converse_jar_QA/bin/jdk1.8.0_131/bin/java
-javaagent:/opt/jacoco/lib/jacocoagent.jar
=destfile=/opt/converse_jar_QA/jacoco.exec
-jar /opt/converse_jar_QA/bin/converse.ws.jar
spring.config.location=/opt/converse_jar_QA/bin/application.properties
${t1} 2>&1 &
配置Jacoco,官网地址: https://www.eclemma.org/jacoco/
JaCoCo Java Code Coverage Library
JaCoCo is a free code coverage library for Java, which has been created by the EclEmma team based on the lessons learned from using and integration existing libraries for many years.
解压到\opt\jacocoagent,
安装 Jacocoagent.jar,
tomcat:在目录下面/opt/taobao/tomcat/bin新建一个文件setenv.sh文件,内容如下:
export CATALINA_OPTS="-javaagent:/opt/jacoco/lib/jacocoagent.jar=destfile=jacoco.exec"
下面blog比较详细测试了代码覆盖率这个玩意儿,有空可以看看,自己也试试,mark下
https://blog.****.net/ohcezzz/article/details/78416125
还有一些关于定义和原理的介绍:
https://blog.****.net/gc_cg/article/details/53172053
关于JAVA代码覆盖率工具JaCoCo,作者会通过三篇来介绍,分别为原理篇、实践篇和踩坑篇,先从原理篇开始介绍~
一、覆盖率定义
作为一个测试人员,保证产品的软件质量是其工作首要目标,为了这个目标,测试人员常常会通过很多手段或工具来加以保证,覆盖率就是其中一环比较重要的环节。
我们通常会将测试覆盖率分为两个部分,即“需求覆盖率”和“代码覆盖率”。
需求覆盖:指的是测试人员对需求的了解程度,根据需求的可测试性来拆分成各个子需求点,来编写相应的测试用例,最终建立一个需求和用例的映射关系,以用例的测试结果来验证需求的实现,可以理解为黑盒覆盖。
代码覆盖:为了更加全面的覆盖,我们可能还需要理解被测程序的逻辑,需要考虑到每个函数的输入与输出,逻辑分支代码的执行情况,这个时候我们的测试执行情况就以代码覆盖率来衡量,可以理解为白盒覆盖。
以上两者完全可以相辅相成,用代码覆盖结果反向的检查需求覆盖(用例)的测试是否充分完整。
如果做覆盖率测试?我们可以借助一些网上流行的各种覆盖率工具,本章主要介绍JaCoCo这个工具。
二、JAVA覆盖率工具介绍
市场上java主要代码覆盖率工具:EMMA、JaCoCo。
总结一下个人对JaCoCo优势的理解:
(1) JaCoCo支持分支覆盖、引入了Agent模式。
(2) EMMA官网已经不维护了,JaCoCo是其团队开发的,可以理解为一个升级版。
(3) JaCoCo社区比较活跃,官网也在不断的维护更新。
我们前期使用的EMMA,也做了全量、差异覆盖率,和精准耦合也结合在了一起,但后来考虑到JaCoCo的优势,也就全部切换了过来。
2.1 JaCoCo简述
JaCoCo是一个开源的覆盖率工具(官网地址:http://www.eclemma.org/JaCoCo/),它针对的开发语言是java,其使用方法很灵活,可以嵌入到Ant、Maven中;可以作为Eclipse插件,可以使用其JavaAgent技术监控Java程序等等。
很多第三方的工具提供了对JaCoCo的集成,如sonar、Jenkins等。
JaCoCo包含了多种尺度的覆盖率计数器,包含指令级覆盖(Instructions,C0coverage),分支(Branches,C1coverage)、圈复杂度(CyclomaticComplexity)、行覆盖(Lines)、方法覆盖(non-abstract methods)、类覆盖(classes),后面会一一介绍。
我们先看看其覆盖率结果展现如下图1-1所示,方便读者先有一个大概的了解。
图1-1 覆盖率报告结果部分截图
标示绿色的为行覆盖充分,标红色的为未覆盖的行,黄色菱形的为分支部分覆盖,绿色菱形为分支完全覆盖。
通过这个报告的结果就可以知道代码真实的执行情况,便于我们分析评估结果。
2.2 JaCoCo基本概念
行覆盖率:度量被测程序的每行代码是否被执行,判断标准行中是否至少有一个指令被执行。
类覆盖率:度量计算class类文件是否被执行。
分支覆盖率:度量if和switch语句的分支覆盖情况,计算一个方法里面的总分支数,确定执行和不执行的 分支数量。
方法覆盖率:度量被测程序的方法执行情况,是否执行取决于方法中是否有至少一个指令被执行。
指令覆盖:计数单元是单个java二进制代码指令,指令覆盖率提供了代码是否被执行的信息,度量完全 独立源码格式。
圈复杂度:在(线性)组合中,计算在一个方法里面所有可能路径的最小数目,缺失的复杂度同样表示测 试案例没有完全覆盖到这个模块。
2.3 JaCoCo 原理1、注入方式介绍
这个图包含了几种不同的收集覆盖率信息的方法,每种方法的实现方法都不一样,带颜色的部分是JaCoCo比较有特色的地方。
上面各个名次含义(带颜色的为JaCoCo支持):
上表JaCoCo支持的部分,再详细的解释下:
(1) JaCoCo在Byte Code时使用的ASM技术修改字节码方法,可以修改Jar文件、class文件字节码文件。
(2) JaCoCo同时支持on-the-fly和offline的两种插桩模式。
On-the-fly插桩:
JVM中通过-javaagent参数指定特定的jar文件启动Instrumentation的代理程序,代理程序在通过Class Loader装载一个class前判断是否转换修改class文件,将统计代码插入class,测试覆盖率分析可以在JVM执行测试代码的过程中完成。
Offline模式:
在测试前先对文件进行插桩,然后生成插过桩的class或jar包,测试插过桩 的class和jar包后,会生成动态覆盖信息到文件,最后统一对覆盖信息进行处理,并生成报告。
On-the-fly和offline比较:
On-the-fly模式更方便简单进行代码覆盖分析,无需提前进行字节码插桩,无需考虑classpath 的设置。
存在如下情况不适合on-the-fly,需要采用offline提前对字节码插桩:
(1) 运行环境不支持java agent。
(2) 部署环境不允许设置JVM参数。
(3) 字节码需要被转换成其他的虚拟机如Android Dalvik VM。
(4) 动态修改字节码过程中和其他agent冲突。
(5) 无法自定义用户加载类。
2、JaCoCo执行最小的java版本
最小需要Java1.5
3、字节码处理方式
JaCoCo通过注入来修改和生成java字节码,使用的是ASM库。
4、java方法控制流分析
JaCoCo是如何在字节码注入的?
我们带着疑问来看下面的内容:
先举个实例,有个java方法:
编译后转换成字节码后,内容如下:
我们知道JaCoCo是字节码注入方式,它是通过一个Probe探针的方式来注入的,具体如下:
探针是字节指令集插入到java方法中,程序执行后可以被记录,它不会改变原有代码的行为。
我们看看探针前后插入比较:
颜色的部分就是探针注入的地方。
JaCoCo是根据控制流Type来采用不同的探针插入策略的。
一个用java字节码定义的java方法的控制流图可能有以下的type,每一个type连接一个源指令与目标指令,type不同探针的注入策略也会不同,如下是type定义:
探针不改变该方法的行为,但记录他们已被执行的事实,从理论上讲,可以在控制流图的每一个边插入一个探针,作为探针实现本身需要多个字节码指令,这将增加几倍的类文件的大小和执行速度。
事实上,只需要一个几个探头,根据每个方法的控制流的方法,下面说明了如何在不同的边缘类型的情况下添加额外的指令:
一个instrumented class可以用以下代码检索其探针数组实例:
JaCoCo是用一个布尔数组来实现探针,每个探针对应于该数组中的项。当以下四个字节码指令触发时探针进行输入设置为true:
JaCoCo对行探针是这样处理的,添加两行指令之间的一个额外的探针时,后续行至少包含一个方法调用。
以上是JaCoCo插桩原理,如果想深入了解,可以去看看它的源码实现。
三、JaCoCo使用方式
使用方式有很多,这里贴出了相应的参考链接,根据项目的不同可以灵活供有需要的读者去学习。
3.1 Apache Ant方式
参见 http://eclemma.org/jacoco/trunk/doc/ant.html
主要有以下几种,具体使用就不介绍了,应用宝是用的这种方式,后续有介绍。
Task coverage、Task agent、Task dump、Task merge、Task report、Task instrument
3.2 命令行方式
参见 http://www.eclemma.org/jacoco/trunk/doc/agent.html
使用方式说明:
主要放在JAVA_OPTS中,比如:
由AgentOptions的getVMArgument方法加载,各参数入AgentOptions的对应参数,为后续操作做为输入。
下面是官网的所有参数说明:
系统在jvm停止的时候会dump覆盖率信息。
关键的核心代码在这里,Agent.java在有一段代码
Runtime.getRuntime().addShutdownHook这个方法的意思就是在jvm中增加一个关闭的钩子,当jvm关闭的时候,会执行系统中已经设置的所有通过方法addShutdownHook添加的钩子,当系统执行完这些钩子后,jvm才会关闭。所以这些钩子可以在jvm关闭的时候进行内存清理、对象销毁等操作。
也就是在JVM关闭的时候调用agent.shutdown(),也就是写覆盖率数据。
3.3 Apache Maven方式
参见 http://www.eclemma.org/jacoco/trunk/doc/maven.html
这种方式适合Maven的项目。
下面简单说下调用方式原理:
就拿官方的Offline Example来说吧,其部分内容如下:
注意蓝色的部分,上面的配置主要做了以下几个事情:
(1) 项目已jar包方式打包,引入junit和jacoco。
(2) Build时执行instrument、report、check。
(3) 覆盖率生成到target/jacoco.exec
我们看看他是怎么触发调用的。
在jacoco源码中:jacoco-maven-plugin\target\classes\META-INF\maven\org.jacoco\jacoco-maven-plugin目录下有个plugin-help.xml文件,它里面标明了具体的调用方式。
截出instrument这段,关键地方就是下面蓝色部分。
官网上关于参数的说明:
给出一个整理后的表格:
再给一个jacoco的maven部分的代码目录:
到这里,大家应该清楚其调用的方式了吧。
3.4 Eclipse EclDmma Plugin方式
具体步骤如下:
(1) 在Eclipse菜单中选择Help → Install New Software…
(2) 在安装弹框中输入http://update.eclemma.org/,勾选出现的版本。
(3) 核对版本,点击Next。
(4) 根据向导完成安装。
(5) 使用就不说了。
3.5 与Jekins集成
(1) 先要在jenkins上安装JaCoCo的插件,安装完成之后在job的配置项中可以增加这个选项(如图1-2):
图1-2
(2) 选择后出现(图1-3):
图1-3
第一个录入框是你的覆盖率文件(exec),第二个是class文件目录,第三个是源代码文件目录。
(3) 配置好了之后进行构建,构建完成之后job首页就会出现覆盖率的趋势图(图1-4),鼠标点击趋势图可以看到覆盖率详情(图1-5) ,包括具体覆盖率数据和源码的覆盖率情况:
图1-4 趋势图