问题描述
假设我们具有函数foo
。 foo
在其实际代码运行之前检查几个初始条件,这些条件按连续的if条件布置。如果发生错误,则会向用户发出警报/祝酒通知。 if的布局方式如下:
function foo() {
if (!condition_one) {
alert(text_one);
return;
}
if (!condition_two) {
alert(text_two);
return;
}
if (!condition_three) {
alert(text_three);
return;
}
if (!condition_four) {
alert(text_four);
return;
}
// ...
}
在编写此函数之前,我们将根据TDD原理编写第一个单元测试。此第一个测试检查condition_one
失败的情况。第二项测试检查condition_one
是否成功,即text_one
没有收到警报。
我们现在复制第一个测试用例并进行转换,以使其成为检查condition_two
失败的测试。为此,我们必须扩展第一个测试用例,因为我们需要使第一个条件成功才能达到第二个条件。现在,我们为condition_two
编写后续测试,并重复该过程,直到测试完所有初始条件为止。
问题是,每次我们转到下一个条件时,所有先前条件的所有设置代码都会被累积,并且该条件的实际设置代码会变得混乱,很难知道我们正在测试什么
该问题有哪些可能的解决方案?我知道这正是Aspect-Oriented-Programming试图解决的问题,但这不是我的选择。
PS:此问题也出现在其他大型if-else结构中,因此比此特定方案更广泛地适用。
解决方法
我们要做的是设计,而不是仅仅通过设计来获得想要的东西。
答案是,我们需要考虑进行测试的“我们想要什么”,然后才能实现。
在这种情况下,“您想要的”之一就是能够将测试的重要细节与背景噪声区分开。通常可以通过将背景噪声移出测试主体来实现。
摘要中,您的第三个测试大致具有这种形状
assume condition_one
assume not condition_two
foo()
assert alert(text_two)
此描述中的隐含事实是,我们除了关心condition_one和condition_two之外,什么都不关心。
所以在代码中,看起来像
InitialConditions.any()
InitialConditions.condition_one(true)
InitialConditions.condition_two(false)
foo()
assert alert(text_two)
相处融洽,Given
(无论是什么)变得越来越复杂,以至于您可以更精确地表达每个测试的假设-但是,每个测试的散文基本上仍然与细节,而不是整体的复杂性。
Nat Pryce(Test Data Builders(2007))是很好的入门读物。
,就测试而言,如果每个功能不遵循Single Responsibility Principle (SRP),则无法正确测试。从foo
函数中可以看出,条件太多,因此,有一些原因需要更改此方法。在这种方法中,编写测试太难了,有时是不可能的。
我敦促重构此方法以坚持SRP,然后编写测试将是小菜一碟。