测试覆盖率通常被用来衡量测试的充分性和完整性,从广义的角度来讲,测试覆盖率主要分为两大类,一类是面向项目的需求覆盖率,另一类是更偏向技术的代码覆盖率。

  • 需求覆盖率

需求覆盖率是指测试对需求的覆盖率程度,通常的做法是将每一条分解后的软件需求和对应的测试建立一对多的映射关系,最终目标是保证测试可以覆盖每个需求,以保证软件产品的质量。
我们通常采用ALM,Doors和TestLink等需求管理工具来建立需求和测试的对应关系,并以此计算测试覆盖率。需求测试覆盖率统计方法属于传统瀑布型模型下的软件工程实践,传统瀑布模型追求自上而下地指定计划、分析需求、设计软件、编写代码、测试和运维等,在流程上是重量级的,已经很难适应当今互联网时代下的敏捷开发实践。
所以,互联网测试项目中很少直接基于需求来衡量测试覆盖率,而是将软件需求转换成测试需求,然后基于测试需求再来设计测试点。
现在,测试覆盖率通常默认值指代码覆盖率,而不是需求覆盖率。

  • 代码覆盖率

是指至少被执行了一次的条目数占整个条目数的百分比。
(如果“条目数”是语句,对应的就是 代码行覆盖率,如果“条目数”是函数,对应的就是函数覆盖率,如果“条目数”是路径,那么对应的就是路径覆盖率。)

常用的三种代码覆盖率指标:
行覆盖率:又称语句覆盖率,指已经被执行到的语句占总语句可执行语句的百分比。(总可执行语句:不包括类似C++的头文件声明、代码注释空行等等)
判定覆盖率:分支覆盖,用以度量程序中每一个判定的分支是否都被测试到了。即代码中每个判断的取真分支和取假分支是否各被覆盖至少各一次。
条件覆盖:判定中的每个提哦案件的可能取值至少满足一次。

代码覆盖率的价值:统计代码覆盖率仅仅是手段,你必须透过现象看到实物的本质,才能从根本上保证软件整体的质量。统计代码覆盖率的根本目的是找出潜在的遗漏测试用例,并有针对性的进行补充,同时还可以识别出代码中哪些由于需求变更等原因造成的不可达的废弃代码。

我们希望代码覆盖率越高越好,但是测试的成本会随代码覆盖率的提高以类似指数级的方式迅速增加。
高的代码覆盖率不一定能保证软件的质量,但是低的代码覆盖率一定不能保证软件的质量。

  • 代码覆盖率工具
    JaCoCo是一款Java代码的主流开源覆盖率工具,可以很方便地嵌入到Ant、Maven中,并且和很多主流的持续集成工具以及代码静态检查工具,比如Jekins和Sonar等,都有很好的集成。
    该代码覆盖率工具的覆盖率统计报告,包括了每个Java代码文件的行覆盖率以及分支覆盖率统计,并给出了每个Java代码文件的行数、方法数和类数等具体信息。每个Java文件内部也有详细的代码覆盖率情况,绿色的行表示已经被覆盖,红色的行表示尚未被覆盖,黄色的行表示部分覆盖,绿色菱形块表示该分支已经被完全覆盖、黄色菱形块表示该分支仅被部分覆盖。
  • 代码覆盖率工具的实现原理

实现代码覆盖率的统计,最基本的方法就是注入(Instrumentation)。简单地说,注入就是在被测代码中自动插入用于覆盖率统计的探针代码,并保证插入的探针代码不会给原代码带来任何影响。

Android 统计测试覆盖率 测试覆盖率分析_Android 统计测试覆盖率


对于Java代码来讲,根据注入目标的不同,可以分为源代码(Source Code)注入和字节码(Byte Code)注入两大类。基于JVM本身特性以及执行效率的原因,目前主流的工具基本是使用字节码注入,注入的具体实现采用ASM技术。

ASM是一个Java字节码操纵框架,能被用来动态生成类或者增强既有类的功能,可以直接产生class文件,也可以在类被加载入JVM之前动态改变类行为。

根据注入发生的时间点,字节码注入又可以分为两大类模式:On-The-Fly注入模式和Offline注入模式。

On-The-Fly注入模式:
特点:无需修改源代码,也无需提前进行字节码插桩,它适用于支持Java Agent的运行环境。
优点:可以在系统不停机的情况下,实时收集代码覆盖率信息。
缺点:运行环境必须允许使用Java Agent

主要有两种技术方式实现该模式:

  1. 开发自定义的类装载器(Class Loader)实现类装载策略,每次类加载前,需要在class文件中插入探针,早期的Emma就是使用这种方式实现的探针插入。
  2. 借助Java Agent,利用执行在main()方法之前的拦截器方法premain()来插入探针,实际使用过程中需要在JVM的启动参数中添加“-Javaagent”并制定用于实时字节码注入的代理程序,这样代理程序在装载每个class文件前,先判断是否已经插入了探针,如果没有测需要将探针插入class文件中,目前主流的JaCoCo就是使用了这个方式。

Offline注入模式:
该模式也不用修改源代码,但是需要在测试开始之前先对文件进行插桩,并事先生成插过桩的class文件。它适用于不支持Java Agent的运行环境,以及无法使用自定义类装载器的场景。
优点:JVM启动是不用需要使用Java Agent额外开启代理
缺点:无法实施获取代码覆盖率信息,只能在系统停机是下获取

Offline模式根据式生成新的class文件还是直接修改原class文件,又可以分为Replace和Inject两种不同模式,这两种模式在测试运行前就已经通过ASM将探针插入了class文件,而在测试的运行过程中不需要任何额外的处理。Cobertura就是使用Offline模式的典型代表。(Cobertura 是一种开源工具,它通过检测基本的代码,并观察在测试包运行时执行了哪些代码和没有执行哪些代码,来测量测试覆盖率)