示例语句:
if (conditionA && conditionB && conditionC && conditionD) {
return true;
}
我可以为所有 2^4 组合编写单元测试,但如果添加更多条件,这很容易失控。
我的单元测试策略应该是什么来涵盖这样的语句的所有条件?有没有其他方法可以使代码更健壮?
示例语句:
if (conditionA && conditionB && conditionC && conditionD) {
return true;
}
我可以为所有 2^4 组合编写单元测试,但如果添加更多条件,这很容易失控。
我的单元测试策略应该是什么来涵盖这样的语句的所有条件?有没有其他方法可以使代码更健壮?
我看到这种情况的方式是 1 条快乐的道路,以及 4 个潜在的失败点。如果每个条件对于允许返回 true 都是关键的,那么这样写是合理的:
我知道可以编写通过这些检查的逻辑,但是当多个变量为假时实际上返回真......但我真的不会担心这样的情况,除非你在宇宙飞船或生死攸关的东西上工作涉及。在几乎所有情况下,测试人员只是在测试实现是否因任何变量的失败而失败。
关于这个主题已经写了很多,你的问题似乎需要 MC/DC。
有一个谓词由导致决策的多个条件组成。适用于问题中谓词的众所周知的覆盖标准包括:
决策覆盖:确保整个谓词一次为真,一次为假。
这导致两个测试用例,例如 (T,T,T,T) 和 (F,T,T,T)。
基本条件覆盖:确保每个条件都是真假。
这也可以通过两个测试用例来实现:(T,T,T,T) 和 (F,F,F,F)。
请注意,基本条件覆盖不一定意味着决策覆盖(例如:带有测试用例 (T,F) 和 (F,T) 的“P AND Q”满足基本条件覆盖,但都评估为 F,因此无法实现 100% 决策覆盖)。
修正条件/决策覆盖 ( MC/DC )。结合决策和基本条件覆盖,“修改”使其还要求每个条件必须单独确定结果。Edwin Buck的答案是有效的 MC/DC 盖板(TTTT、FTTT、TFTT、TTFT、TTTF)。
一般来说,在 N 个条件下,MC/DC 需要 N+1 个测试用例,而不是 2^N。因此,它在严谨性(测试每个条件)和效率(测试所有 2^4 可能没有必要)之间取得了很好的平衡。这背后的直觉正是亚当贝茨回答中的推理。
全条件覆盖:测试所有 2^N 个可能的组合。
您可能不需要执行所有 2^4 个条件,因为例如,如果 A 为假,则甚至不会检查其他条件。您可能只需 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 的重新排列,并且不依赖短路逻辑来确保捕获失败条件。(贾斯汀的回答也很好,但是通过在他的解决方案中为未检查的值选择真实值,您可以增加测试的表达能力并防止错误消息指示错误的非真实选项,如果您决定以某种方式报告哪个选项是错误的)。
作为对我的回答的介绍,我想再次解释一下我们为什么要进行软件测试。大多数测试人员都存在很大的误解。
然后,这已经是您问题“我的单元测试策略应该是什么?”的一部分的答案。</p>
我将引用汽车 SPICE (PAM 3.1),一个众所周知且经过验证的流程模型,Process SWE.4,软件单元验证:
“软件单元验证过程的目的是验证软件单元,以提供证据证明软件单元符合软件详细设计和非功能性软件要求。”</p>
另一组单元测试描述,对于对质量特别是安全性有更高要求的软件,可以参考 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。
当然,您也可以选择众多其他 Coverage 方法中的一种。但是你应该在你的测试策略中给出一个理由,你为什么这样做。
再看你的问题:
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”也是经过认证和批准的标准。对于那些你需要忘记从真值表上的黑盒视图开始的所有教程。谈到结构覆盖或测试,应该很清楚,只有 WhiteBox 视图才有效。而且,如果您碰巧使用具有布尔快捷评估的语言(例如在 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,您可以查看