作为一个测试人员,保证产品的软件质量是其工作首要目标,为了这个目标,测试人员常常会通过很多手段或工具来加以保证,覆盖率就是其中一环比较重要的环节。

我们通常会将测试覆盖率分为两个部分,即“需求覆盖率”和“代码覆盖率”。

需求覆盖:指的是测试人员对需求的了解程度,根据需求的可测试性来拆分成各个子需求点,来编写相应的测试用例,最终建立一个需求和用例的映射关系,以用例的测试结果来验证需求的实现,可以理解为黑盒覆盖。

代码覆盖:为了更加全面的覆盖,我们可能还需要理解被测程序的逻辑,需要考虑到每个函数的输入与输出,逻辑分支代码的执行情况,这个时候我们的测试执行情况就以代码覆盖率来衡量,可以理解为白盒覆盖。

以上两者完全可以相辅相成,用代码覆盖结果反向的检查需求覆盖(用例)的测试是否充分完整。

如果做覆盖率测试?我们可以借助一些网上流行的各种覆盖率工具,本章主要介绍JaCoCo这个工具。

EMMA与JaCoco比较分析:

市场上java主要代码覆盖率工具:EMMA、JaCoCo

总结一下个人对JaCoCo优势的理解:

(1)JaCoCo支持分支覆盖、引入了Agent模式。

(2)EMMA官网已经不维护了,JaCoCo是其团队开发的,可以理解为一个升级版。

(3)JaCoCo社区比较活跃,官网也在不断的维护更新。

JaCoCo是一个开源的覆盖率工具(官网地址:http://www.eclemma.org/JaCoCo/),它针对的开发语言是java,其使用方法很灵活,可以嵌入到Ant、Maven中;可以作为Eclipse插件,可以使用其JavaAgent技术监控Java程序等等。

##############################如果你不了解什么是java agent,下面接着有介绍,否则直接跳过####################################

JavaAgent 是JDK 1.5 以后引入的,也可以叫做Java代理。

JavaAgent 是运行在 main方法之前的拦截器,它内定的方法名叫 premain ,也就是说先执行 premain 方法然后再执行 main 方法。

那么如何实现一个 JavaAgent 呢?很简单,只需要增加 premain 方法即可。

看下面的代码和代码中的注释说明:

package com.shanhy.demo.agent;import java.lang.instrument.Instrumentation;/*** 我的Java代理** @author   单红宇(365384722)* @myblog  http://blog.csdn.net/catoop/* @create    2016年3月30日*/
public class MyAgent {/*** 该方法在main方法之前运行,与main方法运行在同一个JVM中* 并被同一个System ClassLoader装载* 被统一的安全策略(security policy)和上下文(context)管理** @param agentOps* @param inst* @author SHANHY* @create  2016年3月30日*/public static void premain(String agentOps, Instrumentation inst) {System.out.println("=========premain方法执行========");System.out.println(agentOps);}/*** 如果不存在 premain(String agentOps, Instrumentation inst) * 则会执行 premain(String agentOps)** @param agentOps* @author SHANHY* @create  2016年3月30日*/public static void premain(String agentOps) {System.out.println("=========premain方法执行2========");System.out.println(agentOps);}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

写完这个类后,我们还需要做一步配置工作。

在 src 目录下添加 META-INF/MANIFEST.MF 文件,内容按如下定义:

Manifest-Version: 1.0
Premain-Class: com.shanhy.demo.agent.MyAgent
Can-Redefine-Classes: true
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

要特别注意,一共是四行,第四行是空行,还有就是冒号后面的一个空格,如下截图: 

然后我们打包代码为 myagent.jar

注意打包的时候选择我们自己定义的 MANIFEST.MF 


接着我们在创建一个带有main方法的主程序工程,截图如下: 

然后将该主程序打包为 myapp.jar


如何执行 myagent.jar ?我们通过 -javaagent 参数来指定我们的Java代理包,值得一说的是 -javaagent 这个参数的个数是不限的,如果指定了多个,则会按指定的先后执行,执行完各个 agent 后,才会执行主程序的 main 方法。

命令如下:

java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -javaagent:G:\myagent.jar=Hello3 -jar myapp.jar
  • 1
  • 1

输出结果:

G:\>java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -javaagent:G:\myagent.jar=Hello3 -jar myapp.jar
=========premain方法执行========
Hello1
=========premain方法执行========
Hello2
=========premain方法执行========
Hello3
=========main方法执行========
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

特别提醒:如果你把 -javaagent 放在 -jar 后面,则不会生效。也就是说,放在主程序后面的 agent 是无效的。

比如执行:

java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -jar myapp.jar -javaagent:G:\myagent.jar=Hello3
  • 1
  • 1

只会有前个生效,第三个是无效的。 
输出结果:

G:\>java -javaagent:G:\myagent.jar=Hello1 -javaagent:G:\myagent.jar=Hello2 -jar myapp.jar -javaagent:G:\myagent.jar=Hello3
=========premain方法执行========
Hello1
=========premain方法执行========
Hello2
=========main方法执行========
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

命令中的Hello1为我们传递给 premain 方法的字符串参数。

至此,我们会使用 javaagent 了,但是单单看这样运行的效果,好像没有什么实际意义嘛。

我们可以用 javaagent 做什么呢?下篇文章我们来介绍如何在项目中应用 javaagent。


最后说一下,还有一种,在main方法执行后再执行代理的方法,因为不常用,而且主程序需要配置 Agent-Class,所以不常用,如果需要自行了解下 agentmain(String agentArgs, Instrumentation inst) 方法。

#################################################### java agent介绍结束 #####################################################

很多第三方的工具提供了对JaCoCo的集成,如sonar、Jenkins等。
JaCoCo包含了多种尺度的覆盖率计数器,包含指令级覆盖(Instructions,C0coverage),分支(Branches,C1coverage)、圈复杂度(CyclomaticComplexity)、行覆盖(Lines)、方法覆盖(non-abstract methods)、类覆盖(classes)。

行覆盖率:度量被测程序的每行代码是否被执行,判断标准行中是否至少有一个指令被执行。

类覆盖率:度量计算class类文件是否被执行。

分支覆盖率:度量if和switch语句的分支覆盖情况,计算一个方法里面的

总分支数,确定执行和不执行的 分支数量。

方法覆盖率:度量被测程序的方法执行情况,是否执行取决于方法中是否有至少一个指令被执行。

指令覆盖:计数单元是单个java二进制代码指令,指令覆盖率提供了代码是否被执行的信息,度量完全 独立源码格式。

圈复杂度:在(线性)组合中,计算在一个方法里面所有可能路径的最小数目,缺失的复杂度同样表示测 试案例没有完全覆盖到这个模块。

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定义:

JAVA代码覆盖率工具JaCoCo-原理简单分析相关推荐

  1. JAVA代码覆盖率工具JaCoCo-踩坑篇

    JAVA代码覆盖率工具JaCoCo-原理篇和JAVA代码覆盖率工具JaCoCo-实践篇已经给大家介绍过了,本篇为踩坑篇,这里的话题不是说明JaCoCo有什么问题,而是把过程中遇到的几个棘手问题的解决方 ...

  2. Nginx介绍及原理简单分析

    快速入门 ------------------------ 关于Nginx,我们可以到其官网 http://nginx.org/  以及WIKI http://wiki.nginx.org 进行下载和 ...

  3. 岭回归原理简单分析与理解

    岭回归原理简单分析与理解 首先说明一下,岭回归用于回归.学习岭回归,给我的感受是,它的数学公式推导比较简单,然而理解其含义相对难一些,所以本文着重引导你去理解它,而不仅仅是会推导公式.至于背景介绍,网 ...

  4. Java覆盖率工具jacoco,Cobertura

    最近研究Java覆盖率工具,了解到了jacoco,Cobertura这两款,但是Cobertura没有维护了,不支持新的java语法.下面简单介绍一下这两个工具的使用. 简介 市场上主要代码覆盖率工具 ...

  5. java lock park_java并发编程-LockSupport中park与unpark基本使用与原理简单分析

    文章目录 java并发编程原理之---park与unpark 基本使用 情况一,先park再unpark,代码举例与分析 情况二,先unpark再park,代码举例与分析 特点 原理之park &am ...

  6. java测试覆盖率工具_【腾讯TMQ】JAVA代码覆盖率工具JaCoCo-原理篇(下)

    三.JaCoCo使用方式 使用方式有很多,这里贴出了相应的参考链接,根据项目的不同可以灵活供有需要的读者去学习. 3.1 Apache Ant方式 参见 http://eclemma.org/jaco ...

  7. Flink教程(05)- Flink原理简单分析

    文章目录 01 引言 02 Flink角色 03 Flink执行流程 3.1 Standalone版本 3.2 on yarn 04 Flink Streaming Dataflow 4.1 Flin ...

  8. @EnableAutoConfiguration原理简单分析

    一.源码分析简述 声明:本人使用的开发工具为IDEA 1.@EnableAutoConfiguration了解 查看源码,眼睛扫到@Import(AutoConfigurationImportSele ...

  9. Dubbo原理简单分析

    1.Dubbo原理分析 alibaba有好几个分布式框架,主要有:进行远程调用(类似于RMI的这种远程调用)的(dubbo.hsf),jms消息服务(napoli.notify),KV数据库(tair ...

最新文章

  1. 如何让网站被百度谷歌快速收录
  2. Revit二次开发--Hello World
  3. 微信客服系统开发SDK使用教程- 拉取当前微信个人号列表请求(立即)
  4. 简单的作好服务器安全的几个步骤
  5. testTry-catch和catch中的应用程序恢复
  6. 考前必背的50个知识点——系统集成项目管理工程师考试
  7. 2013Esri中国用户大会,show应用,赢大奖--获奖名单公布!
  8. 回归分析-常用统计量含义解析
  9. html梯形选项卡,css 梯形tab标签页
  10. 设置TextView滚动
  11. 阿里高维向量检索方法NSG介绍
  12. 激光三角测量物体高度
  13. 零基础语法入门第四讲 代词的主格和宾格
  14. 51单片机直流电机PID速度控制正反转控制(红外光电测速)LCD1602 L298N
  15. 低代码数字孪生平台,魅力何在?
  16. 数学分析:数项级数的概念
  17. 把仙剑奇侠传5的音乐从pkg里请出来变成mp3吧
  18. 编译Android8,【分享】为MPSoC编译Android 8的主要流程和命令
  19. 窗口-视口转换(详细)
  20. Fraps 游戏录像工具

热门文章

  1. pynlpir(ICTCLAS)初步使用
  2. JEPaaS笔记||学习培训资料||案例视频 【全套】
  3. Cacti auth.php,Cacti微信企业号图文报警
  4. efcore根据多个条件更新_EF Core 基础知识
  5. Linux Redhat5.7系统配置网易的yum源
  6. 知道自己想要什么,保持自己的节奏。
  7. 5种最流行的AI编程语言
  8. ReactiveCocoa 更优雅的编程(信号探秘)
  9. nginx端合并JS
  10. 【CSS进阶】box-shadow 与 filter:drop-shadow 详解及奇技淫巧