目录
[1. 语句覆盖 (Statement Coverage)](#1. 语句覆盖 (Statement Coverage))
[2. 判定覆盖 (Decision Coverage) / 分支覆盖](#2. 判定覆盖 (Decision Coverage) / 分支覆盖)
[3. 条件覆盖 (Condition Coverage)](#3. 条件覆盖 (Condition Coverage))
[4. 判定/条件覆盖 (Decision/Condition Coverage)](#4. 判定/条件覆盖 (Decision/Condition Coverage))
[5. 条件组合覆盖 (Multiple Condition Coverage)](#5. 条件组合覆盖 (Multiple Condition Coverage))
[6. 路径覆盖 (Path Coverage)](#6. 路径覆盖 (Path Coverage))
白盒测试的逻辑覆盖法听起来名词很多,容易混淆,但其实它们就像是"给代码做体检的不同颗粒度"------从粗到细,看看你的测试用例到底跑过了代码的哪些角落。
为了让你更好地理解,我们先设定一段经典的、带有两个判断逻辑的示例代码作为我们的"靶子"。
java
void testLogic(int a, int b, int x) {
// 判定 1 (包含条件 C1 和 C2)
if (a > 1 && b == 0) {
x = x / a; // 语句 1
}
// 判定 2 (包含条件 C3 和 C4)
if (a == 2 || x > 1) {
x = x + 1; // 语句 2
}
}
在这段代码中:
-
判定 (Decision/Branch): 指的是整个
if后面的大括号里的判断结果(真或假)。这里有两个判定:判定1和判定2。 -
条件 (Condition): 指的是构成判定的最小逻辑单元。这里有四个条件:
C1: a>1、C2: b==0、C3: a==2、C4: x>1。
接下来,我们用这段代码把这 6 种覆盖法逐一击破。
1. 语句覆盖 (Statement Coverage)
目标: 让程序里每一行可执行的代码,至少都执行一次。
-
通俗理解: 走马观花,每一行代码我都要走到。这是最基础的覆盖,强度最弱。
-
用例设计: 我们只需要让
判定1和判定2都为真,就能走进大括号里执行语句1和语句2。-
用例:
a = 2, b = 0, x = 4 -
执行过程: *
判定1: 2 > 1 且 0 == 0(真),执行x = 4 / 2 = 2。(覆盖了语句1)判定2: 2 == 2 或 2 > 1(真),执行x = 2 + 1 = 3。(覆盖了语句2)
-
-
缺点: 无法发现隐藏在分支(比如条件为假时)里的逻辑错误。
2. 判定覆盖 (Decision Coverage) / 分支覆盖
目标: 让程序里每一个判定(if)的"真 (True)"和"假 (False)"分支都至少走一次。
-
通俗理解: 每一个路口的左拐和右拐,我都要走一遍。
-
用例设计: 需要
判定1 (T, F)和判定2 (T, F)。-
用例1:
a = 2, b = 0, x = 4-> 判定1(真),判定2(真)。 -
用例2:
a = 1, b = 1, x = 1-> 判定1(假),判定2(假)。
-
-
缺点: 判定覆盖只看最终结果,不看判定内部的条件。比如
判定1是假,可能是因为a<=1,也可能是因为b!=0,它没有对内部细节进行充分测试。
3. 条件覆盖 (Condition Coverage)
目标: 让判定里面的每一个独立条件,都至少取一次"真"和"假"。
-
通俗理解: 我不管你整个判定是真是假,我只要求组成判定的各个小零件(C1, C2, C3, C4)都分别变过一次红绿灯。
-
用例设计:
-
C1:
a>1(T/F) -
C2:
b==0(T/F) -
C3:
a==2(T/F) -
C4:
x>1(T/F) (注意这里的 x 是经过第一步运算后的 x) -
用例1:
a = 2, b = 0, x = 4-> C1(T), C2(T), 此时 x=2 -> C3(T), C4(T)。 -
用例2:
a = 1, b = 1, x = 1-> C1(F), C2(F), 此时 x=1 -> C3(F), C4(F)。
-
-
盲区提醒: 满足了条件覆盖,不一定 满足判定覆盖!如果有个判定是
if (A || B),你设计的用例是(A=T, B=F)和(A=F, B=T),满足了条件覆盖,但整个判定结果都是 True,缺少了 False 分支的覆盖。
4. 判定/条件覆盖 (Decision/Condition Coverage)
目标: 小孩子才做选择,大人全都要。既要满足"判定覆盖",又要满足"条件覆盖"。
-
通俗理解: 每个路口的左右拐要走一遍,且决定拐向的每一个小零件的正反面也要翻一遍。
-
用例设计: 刚好上面【3. 条件覆盖】中设计的两个用例
a=2, b=0, x=4和a=1, b=1, x=1,不仅让所有小条件都取了真假,同时也让判定1和判定2的整体结果都取了真假。所以这组用例也满足判定/条件覆盖。
5. 条件组合覆盖 (Multiple Condition Coverage)
目标: 针对每一个判定内部,所有可能的"条件真假组合"都要执行一次。
-
通俗理解: 穷举法。判定1有两个条件,就有 2x2=4 种组合;判定2有两个条件,也有 4 种组合。
-
用例设计: * 对于
判定1 (a>1, b==0),需要覆盖:(T,T), (T,F), (F,T), (F,F)。-
对于
判定2 (a==2, x>1),需要覆盖:(T,T), (T,F), (F,T), (F,F)。 -
你需要设计多个用例,确保这 8 种局部组合都被触发过。这是非常强的一种覆盖方式,但用例数量会显著增加。
-
6. 路径覆盖 (Path Coverage)
目标: 覆盖程序中所有可能的完整执行路径。
-
通俗理解: 从起点到终点,不管中间怎么绕,所有能走通的完整路线都要走一遍。
-
用例设计: 我们的代码有两个连续的判断,相当于两条连续的分岔路,因此有 2 \\times 2 = 4 条路径:
-
判定1(真) -> 判定2(真)
-
判定1(真) -> 判定2(假)
-
判定1(假) -> 判定2(真)
-
判定1(假) -> 判定2(假)
-
-
特点: 路径覆盖能发现最深层次的组合错误,但如果代码里有循环(比如
while循环跑 100 次),路径数量会爆炸(无穷大),所以实际中通常会对循环次数进行限制。
总结与对比
| 覆盖方法 | 关注焦点 | 覆盖强度 | 缺陷 |
|---|---|---|---|
| 语句覆盖 | 每一行代码 | 弱 | 最基础,漏测率极高 |
| 判定(分支)覆盖 | T/F 结果 | 较弱 | 忽略了内部复杂的条件组合 |
| 条件覆盖 | 每个内部条件 | 较弱 | 可能会漏掉判定的某个分支 |
| 判定/条件覆盖 | T/F 结果 + 内部条件 | 中等 | 依然没有覆盖条件的所有组合 |
| 条件组合覆盖 | 内部条件的各种组合 | 强 | 用例数量多,设计成本高 |
| 路径覆盖 | 完整的执行流 | 最强 (理论上) | 存在循环时,用例数呈指数级爆炸 |