示例语句:
if (conditionA && conditionB && conditionC && conditionD) {
return true;
}
我可以为所有 2^4 种组合编写单元测试,但如果添加更多条件,这很容易失控。
我的单元测试策略应该是什么来涵盖此类语句的所有条件?有没有其他方法可以使代码更健壮?
我看到这种情况的方式是 1 条快乐的道路和 4 个潜在的故障点。如果每个条件对于允许返回 true 都至关重要,那么编写以下内容是合理的:
- 单个快乐路径单元测试,这是逻辑返回 true 的唯一情况。和 对
- 可能导致检查失败的每个变量进行单元测试,断言单个变量具有阻止条件通过的功能。
我知道可以编写通过这些检查的逻辑,但是当多个变量为假时实际上返回 true......但我真的不会担心这样的情况,除非你在宇宙飞船或涉及生/死的事情上工作。在几乎所有情况下,测试人员只是测试实现是否在任何变量失败时失败。
关于这个话题已经写了很多,你的问题似乎需要 MC/DC。
有一个由多个条件组成的谓词,导致决策。 适用于问题中谓词的众所周知的覆盖标准包括:
-
决策覆盖率:确保整个谓词一次为真,一次为假。
这导致了两个测试用例,例如 (T,T,T,T) 和 (F,T,T,T)。 -
基本条件覆盖范围:确保每个条件都为真和假。
这也可以通过两个测试用例来实现:(T,T,T,T)和(F,F,F,F)。
请注意,基本条件覆盖不一定意味着决策覆盖(例如:"P 和 Q"与测试用例 (T,F) 和 (F,T) 满足基本条件覆盖,但两者都评估为 F,因此不能实现 100% 决策覆盖)。 -
修改条件/决策覆盖率 (MC/DC)。决策和基本条件覆盖率的结合,"修改"使得它还要求每个条件必须单独决定结果。Edwin Buck的答案是有效的MC/DC封面(TTTT,FTTT,TFTT,TTFT,TTTF)。
一般来说,在 N 个条件下,MC/DC 需要 N+1 个测试用例,而不是 2^N。因此,它在严谨性(测试的每个条件)和效率(可能不需要测试所有 2^4)之间取得了良好的平衡。这背后的直觉正是亚当·贝茨(Adam Bates)在回答中的推理。 -
全条件覆盖:测试所有 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,您可以了解
微直流