基本与复合条件覆盖

Basic vs. compound condition coverage

我正在努力了解这两个覆盖标准之间的差异,但我无法弄清楚它们有何不同。我想我没能准确理解什么是决策覆盖率。我的软件测试教科书指出,复合决策覆盖可能代价高昂(n 个基本条件的 2n 组合)。

我原以为基本条件保险会更贵。

考虑 a && b && c && d && e。我的理解是,在基本条件覆盖中,这些原子变量中的每一个都必须在测试用例中具有值 TRUE 和 FALSE 才能使测试用例具有基本条件充分性——这是 32 个不同的测试用例。

那么实际的区别是什么,所谓的 "basic condition"。上例中,a是基本条件吗?

谢谢。

关于术语,我手头没有使用确切术语 "basic condition coverage" 和 "multiple condition coverage" 的单一来源。 Binder 的 "Testing Object-Oriented Systems" 表示 "condition coverage" 和 "multiple-condition coverage"。 Everett & McLeod 的 "Software Testing" 表示 "simple condition coverage" 和 "compound condition coverage"。但我敢肯定,在每种情况下,第一项是您的 "basic condition coverage",第二项是您的 "compound condition coverage"。我将在下面使用这些术语。

基本条件覆盖是指程序中的每个基本条件在某些测试中为真,在某些测试中为假,而不管其他条件。在下面

if a && b && c
  # do stuff
else
  # do other stuff
end

有一个复合条件 a && b && c,具有三个基本条件 abc。只需要两个测试用例,一个所有基本条件都为真,一个所有基本条件都为假,就可以获得完整的基本条件覆盖。基本条件恰好是复合条件的一部分并不重要。

注意基本条件覆盖不是分支覆盖。如果复合条件是a && b && !c,上面这两个测试用例仍然可以实现基本条件覆盖,但不会实现分支覆盖。

用于基本条件覆盖的一组不太积极优化的测试用例将有一个测试用例,其中所有三个基本条件都为假,三个测试用例中每个测试用例的不同基本条件为真。那仍然只是复合条件中基本条件八种可能组合中的四种。我们忽略其他四个的不舒服的感觉就是为什么有复合条件覆盖。这需要对复合条件中基本条件的每种可能组合进行测试。在上面的示例中,您需要八个测试,一个用于 abc 的可能值的每种可能组合,以获得完整的复合条件覆盖。

首先,决定条件的区别。

一个条件是一个原子布尔表达式,不能分解成更简单的布尔表达式。例如:a(如果 a 是布尔值)。

A Decision 是具有零个或多个布尔运算符的条件的组合。没有操作员的决定也是一个条件。例如:(a or b) and c 还有 a and b 或只是 a.

举个简单的例子

if(decision)  {
  //branch 1
} else {
  //branch 2
}

您需要两个测试来覆盖两个分支。这就是 决策覆盖率 分支覆盖率 。如果decision是一个条件(即a),也叫基本条件覆盖,也就是对一个条件的两个分支的覆盖

decision可以分解为条件

举个例子

decision = (a or b) and c

决策覆盖率将通过

实现
  • a,b,c = 0
  • a,b,c = 1

但其布尔子表达式的所有组合的排列是全条件覆盖多条件覆盖),即基本条件覆盖的化合物

| a | b | c |
| 0 | 0 | 1 |
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 0 | 1 | 0 |
| 1 | 0 | 1 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
| 1 | 1 | 0 |

那将是相当多的测试,但其中一些是多余的,因为其他条件涵盖了某些条件。这反映在 Modified Condition/Decision Coverage (MC/DC) 中,它是 condition coverage函数覆盖率.

对于MC/DC,要求每个条件都必须独立影响结果。通过上述测试(全部为 0 或全部为 1),我们忽略了一个事实,如果 a 和 b 为 0,则 c 值无关紧要,或者,如果 a 和 c 为 1,则 b 值无关紧要。

所以你还是坐下来动动脑筋,想一想哪些组合的整体结果R是1或者0。

  | a | b | c | a or b | c | R |  eq
1 | 0 | 0 | 0 |    0   | 0 | 0 |  A
2 | 0 | 0 | 1 |    0   | 1 | 0 |  B
3 | 0 | 1 | 0 |    1   | 0 | 0 |  A
4 | 0 | 1 | 1 |    1   | 1 | 1 |  C
5 | 1 | 0 | 0 |    1   | 0 | 0 |  A
6 | 1 | 0 | 1 |    1   | 1 | 1 |  D
7 | 1 | 1 | 0 |    1   | 0 | 0 |  A
8 | 1 | 1 | 1 |    1   | 1 | 1 |  D

最后一列显示等效项 class:

  • A:c=0,结果为0,a和b都没有影响
  • B:a,b = 0,结果为0,c无影响
  • C: b,c = 1,结果为1,a无影响
  • D:a,c = 1,结果为1,b无影响

对于 B 和 C,选择哪个是很明显的,对于 A 和 D 则不然。对于每个你必须检查,如果我替换运算符会发生什么,即 or -> and, and -> or ,这将如何影响(子)决定的结果。如果结果会受到影响,你有一个候选人 - 如果没有,你没有。

  • A : (0 and/or 0) and/or 0 -> 无所谓
  • A : (0 and 1) vs (0 or 1) -> 很重要! -> 候选人
  • A : (1 and 0) vs (1 or 0) -> 很重要! -> 候选人
  • A : (1 and/or 1) -> 无所谓
  • D : (1 and 0) vs (1 or 0) -> 重要 -> 候选人
  • D : (1 and 1) -> 无关紧要

所以你得到了上面提到的最终测试集:

  • a = 0, b = 1, c = 0 -> 假分支 (A) OR a = 1, b = 0, c = 0
  • a = 0, b = 0, c = 1 -> 假分支 (B)
  • a = 0, b = 1, c = 1 -> 真分支 (C)
  • a = 1, b = 0, c = 1 -> 真分支 (D)

尤其是后一种测试 - 更改运算符 - 可以使用变异测试等工具来完成,这些工具不仅可以替换运算符,还可以做更多的事情,即翻转操作数、删除语句、更改执行顺序、替换return 值等。对于代码的每次更改,它都会验证测试是否确实失败。这是测试套件质量的良好指标,可确保不仅覆盖了代码,而且您对代码的测试实际上是有效的。

关于术语,我在某处找不到术语 "Compound Decision Coverage"。在我看来,"compound decision" 将是条件的复合,换句话说:条件的复合。