我读过一篇关于TDD的研究,其中一个常见问题(开发人员之间的调查)表示他们并没有真正让测试失败。然后作者说:
如果新测试没有失败,程序员会收到一个指示 生产代码没有按照他们的想法和代码工作 修订可能是必要的。可能发生的另一个问题是 程序员无法确定测试通过的原因;没有 确保新代码实际上对它负责。考试 从一开始就实施可能是错误的。
我想知道,TDD测试怎么能首先通过(因为他们提到的生产代码),如果它在单位级别?我的意思是,如果所有人都被嘲笑(存根......),它应该始终是孤立的,因此永远不能真正先通过。
答案 0 :(得分:3)
假设您有两个课程Calculator
和Formatter
。
Calculator
根据输入计算一些值,Formatter
将值转换为字符串进行显示。
您已在FormatterTest
中进行了一些测试:
test_value_is_formatted_as_number
test_empty_is_formatted_as_NA
现在您实施新功能Show zero values as N/A
。
在TDD之后,您将向Formatter
test_zero_is_formatted_as_NA
添加一项测试,该测试首先检查此项并且您希望它失败:
def test_zero_is_formatted_as_NA(self):
assert formatter.format(0) == 'N/A'
但碰巧它通过了,原因是Formatter
已经这样做但Calculator
返回浮动零,其精度有限。
def format(value):
if value == 0 or value is None:
return 'N/A'
return format_as_string(value)
所以测试通过但是如果你写另一个测试它会失败:
def test_very_small_number_is_treated_as_zero_and_formatted_as_NA(self):
assert formatter.format(0.00000001) == 'N/A'
答案 1 :(得分:0)
通常情况下,您描述的情况很容易发生在某些事情已经实施但系统的另一部分(使用此实现的部分)以某种方式限制它,例如通过更强的先决条件。然后,如果你不熟悉代码,你可能会遇到这样的惊喜。
考虑这个例子:
public string ShowScoreEvaluation(byte points)
{
switch(points)
case 3:
return "You are good!";
case 2:
return "Not bad!";
case 1:
return "Quite bad";
case 0:
return "You suck!"
}
//caller code
if (Points>0)
ShowScoreEvaluation(points)
在上面的代码中,当Points = 0时,调用代码不期望调用该方法。也许在该方法的实现过程中,即使对于points = 0的情况,程序员也只是把它放在那里(作为一个笑话或占位符)。
现在想象一下,你加入这个项目并得到一个新的请求“当玩家有0分时,显示一个令人鼓舞的消息blabla”。 你用Points = 0编写一个单元测试,并期望一个长度> 0的字符串...并且它没有失败,尽管你会期望它。