一、概念
覆盖率:用来度量测试完整性的一个手段,大体可划分为逻辑覆盖
和功能覆盖
覆盖率 = (至少被执行一次的 item 数)/ item 的总数
二、常用的逻辑覆盖
覆盖率中最常见的是逻辑覆盖率(Logic Coverage)
,也叫代码覆盖率 (Code Coverage)或结构化覆盖率(Structural Coverage)
逻辑覆盖属于白盒测试的范畴。常用逻辑覆盖包括:语句覆盖、判定覆盖、条件覆盖、判定条件覆盖、路径覆盖等。
1. 语句覆盖
测试用例在被测程序在运行时,保证每个可执行语句至少执行一次
语句覆盖(Statement Coverage)
是逻辑覆盖中最简单的覆盖,容易理解,易于维护,比较适合自动化
语句覆盖率 = (至少被执行一次的语句数量)/ (可执行的语句总数)
举个栗子:
if CONDITION DO_SOMETHING
ANOTHER_STATEMENT
只要 CONDITION = TRUE 就可以实现语句覆盖。
2. 判定覆盖
判定覆盖(Decision Coverage)
也叫分支覆盖(Branch Coverage), 测试用例在被测程序运行时,保证程序中每个判断至少取一次 TRUE
和 FALSE
判断
覆盖率 = (判定结果至少被评价一次的数量)/ (判定结果的总数)
if A AND B DO_SOMETHING
elseDO_SOMETHING_ELSE
判定覆盖的case:
case1: A = TRUE, B = TRUE
case2: A = TRUE, B = FALSE
优点:针对代码,容易理解,可实现 100% 判定覆盖,测试数据易于维护。
缺点:判定复合条件——代码错误的根源时,可能仅执行特定组合分支被测试 ,完整性高于语句覆盖,低于条件覆盖。
3. 条件覆盖
条件覆盖(Condition Coverage)也叫分支覆盖(Branch Coverage) 测试用例在被测程序运行时,保证程序中每个判断中每个条件至少取一次 TRUE
和 FALSE
条件
覆盖率 = (条件操作数值至少被执行一次的数量)/ (条件操作数值的总数)
举个栗子
if A > 1 AND B = 0 X = X / A
if A = 2 OR X > 1X = X + 1
所有可能的情况:
条件判断 | A > 1 | B = 0 | A = 2 | X > 1 |
---|---|---|---|---|
取真 | A > 1 | B = 0 | A = 2 | X > 1 |
取假 | A <= 1 | B != 0 | A != 2 | X <= 1 |
条件覆盖的case:
case1: A = 2, B = 0, X = 0 TT
case2: A = 0, B = 1, X = 2 FT
优点:容易从设计或代码中被确认,有助于自动化,易于理解和维护,比分支覆盖强
缺点:设计的用例可能不能满足判定覆盖的要求 4. 判定条件覆盖
4. 判定条件覆盖
判定条件覆盖(Dicision Condition Coverage),又叫分支条件覆盖(Branch Condition Coverage,B-C Coverage)
测试用例在被测程序运行时,保证程序中每个判断中每个条件至少取一次 TRUE
和 FALSE
,且么诶个判断本身也至少取一次 TRUE
和 FALSE
判定条件
覆盖率 = (条件操作数值 或 判定结果 至少被执行一次的数量)/ (条件操作数值的总数 + 判定结果总数)
eg:
if A > 1 AND B = 0 X = X / A
if A = 2 OR X > 1X = X + 1
所有可能的情况
判定 | case |
---|---|
A > 1 AND B = 0 | 1. A > 1 AND B = 0 |
A > 1 AND B = 0 | 2. A > 1 AND B != 0 |
A > 1 AND B = 0 | 3. A <= 1 AND B = 0 |
A > 1 AND B = 0 | 4. A <= 1 AND B != 0 |
A = 2 OR X > 1 | 1. A = 2 OR X > 1 |
A = 2 OR X > 1 | 2. A = 2 OR X <= 1 |
A = 2 OR X > 1 | 3. A != 2 OR X > 1 |
A = 2 OR X > 1 | 4. A != 2 OR X <= 1 |
判定覆盖的case
case1: A = 2, B = 0, X = 2 TTTT TT
case2: A = 2, B = 1, X = 0 TFTF FT
case3: A = 0, B = 0, X = 2 FTFT FT
case4: A = 0, B = 1, X = 0 FFFF FF
5. 路径覆盖
路径覆盖(Path Coverage)
测试用例在被测程序运行时,保证覆盖程序中所有可能的路径
路径覆盖率 = (至少一次被执行的路径数)/ (总路径数)
路径覆盖比判定条件覆盖更强,但路径覆盖不能包含判定条件覆盖。
判定覆盖的case
case1(TT): A = 2, B = 0, X = 2
case2(FT): A = 2, B = 1, X = 0
case3(TF): A = 3, B = 0, X = 0
case4(FF): A = 3, B = 1, X = 0
实际代码中,一个较为复杂的程序包含的路径数也是相当庞大的,要完全达到路径覆盖是不可行的,实现自动化路径覆盖也是困难的。
6. 小结
- 即使达到 100% 结构化覆盖率,还是无法保证程序的正确性
- 测试的目的并不是证明程序的正确性,而是要尽可能找出程序中的错误
- 目前,没有十全十美的测试方法,能够发现所有的错误
- 软件测试是有局限性的
三、功能覆盖率
功能覆盖(Function Coverage)
属于黑盒测试的范畴,其中最常见的是需求覆盖。
需求覆盖率 = (被验证的需求数量)/ (总的需求数量)
接口覆盖「入口覆盖」:设计可以测试系统每个接口的用例,属于黑盒测试。
四、面向对象的覆盖率
面向对象:多态性、继承性、封装性
1. 继承上下文覆盖
继承上下文覆盖(Inheritance Context Coverage)
:不是单个度量,是一种传统结构化覆盖的扩展,以考虑方法被继承时的额外接口。
- 基类方法在其上下文空间中的执行完全能独立与其继承类的上下文空间
- 继承类方法在其上下文空间中的执行也独立于其基类的上下文空间
继承上下文判定覆盖率 = (累加每个上下文执行到的判定分支数)/ (上下文数 * 上下文内的判定分支总数)
2. 基于状态的上下文覆盖
基于状态的上下文覆盖(State-based Context Coverage)
:用于改进对带有状态依赖行为的类的测试
面向对象的系统中存在许多类,将其描述为状态机。这些类的对象可以存在于众多不同状态中的一种,而且每个类的行为在每个可能的状态中其性 质是不同的 —— 类的行为依赖与状态
2.1 基于状态的类
eg:有边界的栈 pop() —— 空状态、部分满状态、满状态
2.2 入口点覆盖
黑盒测试角度,接口覆盖(Interface Coverage),或者入口点覆盖(Entry-Point Coverage)
2.3 白盒测试
影响覆盖率的因素 :
- 代码中存在不对应于公共接口特性的判定。eg:错误处理代码 or 保护性代码程序
- 无法确定那些代码被丢失。eg:pop() 方法空状态检查
2.4 基于状态转移图
在不了解类内部细节的基础上,基于类当前状态及类行为的变化,绘制 UML 状态迁移图
测试用例设计目标:执行每个可能状态的每种方法
2.5 基于状态的上下文覆盖
对应于被测类对象的潜在状态,把一个状态上下文内的一个例行程序的执行认为是独立于另一个状态内的相同例行程序的执行。
例行程序必须在每 个适当的上线文(状态)内被执行
基于状态的上下文入口点覆盖率 = (累加每个状态内执行到的方法数)/ (状态数 * 类内方法总数)
3. 基于线程的上下文覆盖
基于线程的上下文覆盖(User-Defined Context Coverage)
:允许将上下文覆盖方法应用于传统结构化覆盖率无法使用的地方,以维护每个线程独 立的覆盖率信息
五、其它覆盖率
1. 函数覆盖
函数覆盖是针对系统或一个子系统的。 在测试中有哪些函数被测试,其被测试到的频率有多大,这些函数在系统所有函数中占的比例有多大
函数覆盖率 = (至少被执行一次的函数数量)/ (系统中函数的总数)
函数覆盖,基于代码,属于白盒测试。易于自动化,也易于理解
2. 指令块覆盖
指令块覆盖(Instruction Blocks Coverage)是语句覆盖的一个变体
指令块表示函数内部的一系列语句,在这一系列语句中不存在控制语句
指令块覆盖率 = (至少被执行一次的指令块数量)/ (系统中指令块的总数)
3. 判定路径覆盖
判定路径覆盖(Decision-to-Decision Paths Coverage, DDP Coverage)是判定覆盖的一个变体
判定指一个序列语句,其起始位置是函数入口或一个判定(eg:if,while,switch等)的开始,结束位置是下一个判定的开始。
DDP覆盖率 = (至少被执行一次的判定路径数量)/ (系统中判定路径的总数)
4. 更改条件判定覆盖
更改条件覆盖(Modified Condition/Decision Coverage, MC/MD Coverage)是判定条件覆盖的一个变体,主要用于多条件测试的情况。
- 被测试程序模块的每个入口点和出口点都必须至少被执行一次,且每个程序判断的结果至少被覆盖一次
- 通过逻辑分解操作,程序的判定被分解为基本的布尔条件表达式,每个条件独立地作用于判定的结果,覆盖所有条件的可能结果
eg:
X and (Y or Z)
所有可能的情况
X | Y | Z | X and (Y or Z) | |
---|---|---|---|---|
Test1 | T | T | T | T |
Test2 | T | T | F | T |
Test3 | T | F | T | T |
Test4 | T | F | F | F |
Test5 | F | T | T | F |
Test6 | F | T | F | F |
Test7 | F | F | T | F |
Test8 | F | F | F | F |
可以组合的case:
Test2,Test6,Test4,Test3
5. 分支条件组合覆盖
分支条件组合覆盖(Branch Condition Combination Coverage),比判定条件覆盖更强的覆盖
测试用例在被测程序运行时,保证每个分支中各操作数值的组织都遍历一次
分支条件组合覆盖率 = (至少被执行一次的分支条件组合)/ (系统中分支条件组合的总数)
X | Y | X or Y | 判定条件覆盖 | 分支条件组合覆盖 | |
---|---|---|---|---|---|
Test1 | T | T | T | √ | √ |
Test2 | T | F | T | √ | |
Test3 | F | T | T | √ | |
Test4 | F | F | F | √ | √ |
6. 过程到过程路径覆盖
过程到过程路径覆盖(Procedure-to-Procedure Path Coverage, PPP Coverage),针对系统或子系统级,用于集成测试 一个PPP对应的是两个函数之前的一个调用关系
PPP覆盖率 = (至少被执行一次的PPP数量)/ (系统中PPP的总数)
7. Z路径覆盖
Z路径覆盖是路径覆盖的一个变体(白盒测试),用于解决程序中存在多个判断和多个循环的问题
程序中存在多个判断和多个循环时,简化循环机制(限制循环次数),以极大程度减少路径的数量,使得覆盖有限的路径成为可能
8. ESTCA 覆盖
错误敏感测试用例分析规则(Error Sensitive Test Cases Analysis,ESTCA),程序中的谓词最容易出错的部分【边界测试】
- 对于 A rel B(rel 可以使 <, = 和 >)型的分支谓词,选择 A 与 B,使得 A < B, A = B, A > B的情况分别出现一次 「检查 rel 的错误」
- 对于 A rel C(rel 可以使 <, = 和 >,A是变量,C是常量)型的分支谓词:「检查 “差一”之类的错误」
- 当 rel 为 < 时,取值 A = C - M(M 是距 C 最小的容许正数,若 A 和 C 均为整型,M = 1);
-
- 当 rel 为 > 时,取值 A = C + M
- 对外部输入变量赋值,使其在每一测试用例中均有不同的值与符号,并于同一组测试用例中其他变量的值与符号不一致「检查程序语句中 的错误」
六、使用覆盖率基本原则
- 覆盖率不是目的,只是一种手段
- 不能针对所有覆盖率指标进行测试,也不能只考虑一种覆盖率指标
- 如果需要付出极大的成员,不要追求绝对 100% 的覆盖率。涉及到生命安全的系统除外
- 使用最少测试用例来达到覆盖