在一个语句中测试多个 AND/OR 条件的覆盖范围



示例语句:

if (conditionA && conditionB && conditionC && conditionD) {
return true;
}

我可以为所有 2^4 种组合编写单元测试,但如果添加更多条件,这很容易失控。

我的单元测试策略应该是什么来涵盖此类语句的所有条件?有没有其他方法可以使代码更健壮?

我看到这种情况的方式是 1 条快乐的道路和 4 个潜在的故障点。如果每个条件对于允许返回 true 都至关重要,那么编写以下内容是合理的:

  1. 单个快乐路径单元测试,这是逻辑返回 true 的唯一情况。和
  2. 可能导致检查失败的每个变量进行单元测试,断言单个变量具有阻止条件通过的功能。

我知道可以编写通过这些检查的逻辑,但是当多个变量为假时实际上返回 true......但我真的不会担心这样的情况,除非你在宇宙飞船或涉及生/死的事情上工作。在几乎所有情况下,测试人员只是测试实现是否在任何变量失败时失败。

关于这个话题已经写了很多,你的问题似乎需要 MC/DC。

有一个由多个条件组成的谓词,导致决策。 适用于问题中谓词的众所周知的覆盖标准包括:

  1. 决策覆盖率:确保整个谓词一次为真,一次为假。
    这导致了两个测试用例,例如 (T,T,T,T) 和 (F,T,T,T)。

  2. 基本条件覆盖范围:确保每个条件都为真和假。
    这也可以通过两个测试用例来实现:(T,T,T,T)和(F,F,F,F)。
    请注意,基本条件覆盖不一定意味着决策覆盖(例如:"P 和 Q"与测试用例 (T,F) 和 (F,T) 满足基本条件覆盖,但两者都评估为 F,因此不能实现 100% 决策覆盖)。

  3. 修改条件/决策覆盖率 (MC/DC)。决策和基本条件覆盖率的结合,"修改"使得它还要求每个条件必须单独决定结果。Edwin Buck的答案是有效的MC/DC封面(TTTT,FTTT,TFTT,TTFT,TTTF)。
    一般来说,在 N 个条件下,MC/DC 需要 N+1 个测试用例,而不是 2^N。因此,它在严谨性(测试的每个条件)和效率(可能不需要测试所有 2^4)之间取得了良好的平衡。这背后的直觉正是亚当·贝茨(Adam Bates)在回答中的推理。

  4. 全条件覆盖:测试所有 2^N 种可能的组合。

您可能不需要执行所有 2^4 个条件,因为例如,如果 A 为 false,则甚至不会检查其他条件。 你也许只能逃脱 5

A   B   C   D
F   X   X   X
T   F   X   X
T   T   F   X
T   T   T   F
T   T   T   T

但正如另一位戴夫所说,根据您的代码,您可能不需要测试所有条件。 考虑一下测试的目标,看看什么是合适的

编辑:avandeursen建议的更改

我会推荐以下方法

A B C D
testTypicalCall()   -> T T T T
testAisFalseFails() -> F T T T
testBisFalseFails(  -> T F T T
testCisFalseFails() -> T T F T
testDisFalseFails() -> T T T F

这捕获了您可能失败的四种独立方式,并且可以推断出,如果其中两种方式组合发生,那么至少应该触发一种失败测试。

在将来重构 if 语句时,它还可以防止 A、B、C 和 D 的重排,并且不依赖于短路逻辑来确保捕获失败条件。 (Justin 的回答也很好,但是通过为他的解决方案中未检查的值选择 true 值,您可以提高测试的表达能力,并防止指示错误的非 true 选项的错误消息,如果您决定以某种方式报告哪个选项是错误的)。

作为我答案的介绍,我想再次解释一下,我们为什么要进行软件测试。大多数测试人员都存在很大的误解。

  • 我们不会测试软件以证明它是无错误的(这是不可能的。已经用于小型复杂软件)
  • 我们执行"建设性测试",以证明功能是可接受的,并且需求或功能正在"工作"。
  • 最重要的是:我们试图找到尽可能多的错误("破坏性测试")。我们永远不会找到所有错误。SRGM可以用来展示测试应该有多深。

然后,这已经是你问题的一部分的答案"我的单元测试策略应该是什么?

我将引用汽车 SPICE (PAM 3.1),一个众所周知且经过验证的过程模型,Process SWE.4,软件单元验证:

"软件单元验证

过程的目的是验证软件单元,以提供证据证明软件单元符合软件详细设计和非功能性软件要求。

另一组单元测试描述,对于对质量,特别是安全性有更高要求的软件,可以取自ISO 26262"道路车辆 - 功能安全 - ",第6部分:软件级别的产品开发",第9章,表10,11,12

软件单元测试的方法

Requirements-based test
Interface test
Fault injection test
Resource usage test
Back-to-back comparison test between model and code, if applicable

为软件单元测试派生测试用例的方法

Analysis of requirements
Generation and analysis of equivalence classes
Analysis of boundary values
Error guessing

现在最重要的是,回答问题的第二部分,你应该做一个结构覆盖分析(不是结构测试),以评估测试用例的完整性,并证明没有意外的功能。切勿混淆结构测试和结构覆盖。

因此,您将测试和检查是否满足要求,并将进行结构覆盖率测量以证明这一点。如果覆盖率结果太低,则将添加更多测试用例。

建议的覆盖指标是 MCDC。

当然,您也可以选择许多其他覆盖方法之一。但是,您应该在测试策略中给出一个理由,为什么要这样做。

再看你的问题:

if (conditionA && conditionB && conditionC && conditionD) 
{
return true;
}

您似乎在寻求结构测试的建议。我也会回答这个问题,但请注意,使用此方法,您只是在测试编译器是否正常工作。

对于手头的布尔表达式(以及其他更复杂的表达式),您可能永远不会发现以下错误之一:

错误类

Expression Negation Fault (ENF)
Sub-Expression Negation Fault (SENF)
Sub-Expression Omission Fault (SEOF)
Literal Negation Fault (LNF)
Literal Omission Fault (LOF)
Literal Reference Fault (LRF)
Literal Insertion Fault (LIF)
Operator Reference Fault (ORF)
Stuck-at-1 Fault (SA1) 
Stuck-at-0 Fault (SA0)
Parenthesis Insertion Fault (PIF)
Parenthesis Omission Fault (POF)
Parenthesis Shift Fault (PSF)

记住,我在开头说过,测试应该发现错误(破坏性测试)。否则,您可能会错过上述错误。

例:

如果您的需求最初打算在表达式中使用"OR"而不是"AND"(错误类 ORF),则使用条件覆盖率,测试向量"TTTT"和"FFFF",将为您提供 100% 的条件覆盖率和 100% 的决策或分支覆盖率。但是你不会找到这个错误。MCDC将揭示问题。

您还提到了测试所有组合(MCC、多条件覆盖)的可能性。对于 4 个变量,这是可以的。但对于更多变量,测试执行持续时间将呈几何级数增长。这是无法管理的。这就是MCDC被定义的原因之一。

现在,让我们假设您的示例语句是正确的,并回到基于 MCDC 的结构测试的测试用例定义。

有几种可用的定义,主要是谈论"唯一原因"MCDC,忽略了这一事实,同时"屏蔽MCDC"和"唯一原因+屏蔽MCDC"也是认证和批准的标准。对于那些需要忘记从真值表上的黑盒视图开始的所有教程。谈到结构覆盖或测试,应该清楚的是,只有白盒视图才能工作。如果你碰巧使用布尔快捷方式计算的语言进行开发(例如在Java,C或C++中),那么WhiteBox视图是强制性的,这一点会更加明显。


对于您的布尔表达式/决策 ("abcd"),并应用布尔快捷方式评估,总共有 16 个唯一原因 MCDC 测试对:

1   Influencing Condition: 'a'  Pair:  0, 15   Unique Cause
2   Influencing Condition: 'a'  Pair:  1, 15   Unique Cause
3   Influencing Condition: 'a'  Pair:  2, 15   Unique Cause
4   Influencing Condition: 'a'  Pair:  3, 15   Unique Cause
5   Influencing Condition: 'a'  Pair:  4, 15   Unique Cause
6   Influencing Condition: 'a'  Pair:  5, 15   Unique Cause
7   Influencing Condition: 'a'  Pair:  6, 15   Unique Cause
8   Influencing Condition: 'a'  Pair:  7, 15   Unique Cause
9   Influencing Condition: 'b'  Pair:  8, 15   Unique Cause
10  Influencing Condition: 'b'  Pair:  9, 15   Unique Cause
11  Influencing Condition: 'b'  Pair: 10, 15   Unique Cause
12  Influencing Condition: 'b'  Pair: 11, 15   Unique Cause
13  Influencing Condition: 'c'  Pair: 12, 15   Unique Cause
14  Influencing Condition: 'c'  Pair: 13, 15   Unique Cause
15  Influencing Condition: 'd'  Pair: 14, 15   Unique Cause

生成推荐的 MCDC 测试集(有多种解决方案):

Test Pair for Condition 'a':    0  15   (Unique Cause)
Test Pair for Condition 'b':    8  15   (Unique Cause)
Test Pair for Condition 'c':   12  15   (Unique Cause)
Test Pair for Condition 'd':   14  15   (Unique Cause)

测试向量:最终结果:0 8 12 14 15

0:  a=0  b=0  c=0  d=0    (0)
8:  a=1  b=0  c=0  d=0    (0)
12:  a=1  b=1  c=0  d=0    (0)
14:  a=1  b=1  c=1  d=0    (0)
15:  a=1  b=1  c=1  d=1    (1)

如果没有布尔快捷方式评估,很明显,您只有 4 个唯一原因 MCDC 测试对:

1  Influencing Condition: 'a'  Pair:  7, 15   Unique Cause
2  Influencing Condition: 'b'  Pair: 11, 15   Unique Cause
3  Influencing Condition: 'c'  Pair: 13, 15   Unique Cause
4  Influencing Condition: 'd'  Pair: 14, 15   Unique Cause

导致一个确定性解决方案:

测试向量:最终结果:7 11 13 14 15

7:  a=0  b=1  c=1  d=1    (0)
11:  a=1  b=0  c=1  d=1    (0)
13:  a=1  b=1  c=0  d=1    (0)
14:  a=1  b=1  c=1  d=0    (0)
15:  a=1  b=1  c=1  d=1    (1)

我希望,我能对这个问题有更多的了解。

如果您想在工具支持下更详细地探索 MCDC,您可以了解

微直流

最新更新