测试驱动开发初始实现

时间:2011-10-07 16:38:22

标签: tdd

TDD的一个常见做法是你做出微小的步骤。但有一件事让我感到烦恼的是我见过的一些人,他们只是硬编码值/选项,然后重构以使其正常工作。例如......

describe Calculator
  it should multiply
    assert Calculator.multiply(4, 2) == 8

然后你尽可能让它通过:

class Calculator
  def self.multiply(a, b)
    return 8

确实如此!

为什么人们会这样做?它是否确保他们实际上在正确的类或其他东西中实现该方法?因为它似乎是一种可靠的方式来引入错误并在忘记某些事情时给予虚假信心。这是一个好习惯吗?

2 个答案:

答案 0 :(得分:5)

这种做法被称为“伪造它,直到你成功。”换句话说,将虚假实现放入其中,直到变得更简单地放入实际实现中。你问为什么我们这样做。

我这样做有很多原因。一个是确保我的测试正在运行。可能配置错误,以便当我点击我的魔术“运行测试”键时,我实际上没有运行测试,我认为我正在运行。如果我按下按钮并且它是红色的,那么放入假的实现并且它是绿色的,我知道我正在运行我的测试。

这种做法的另一个原因是保持快速的红/绿/重构节奏。这就是驱动TDD的心跳,重要的是它具有快速循环。重要的是让你感受到进步,这一点很重要,因此你知道你在哪里。有些问题(显然不是这个问题)无法通过快速心跳来解决,但我们必须在心跳中继续前进。伪造它直到你使它成为确保及时进展的一种方式。另请参阅flow

答案 1 :(得分:4)

有一种思想流派,它可以用来培训程序员使用TDD,它说你不应该有任何原本不属于单元测试的源代码。首先将通过测试的算法编码到测试中,验证您的核心逻辑是否正常工作。然后,将其重构为生产代码可以使用的内容,并编写集成测试以定义交互,从而定义包含此逻辑的对象结构。

此外,宗教TDD遵守会告诉您,应该没有逻辑编码表明需求(由单元测试中的断言验证)没有明确说明。一个很好的例子;在这个时候,系统中唯一的乘法测试是断言答案必须是8.所以,此时,答案总是8,因为要求没有任何不同。

这看起来非常严格,在这样一个简单的案例中,荒谬;为了验证一般情况下的正确功能,当你作为一个聪明的人“知道”乘法应该如何工作并且可以轻松地设置生成并测试乘法表的测试时,你需要无限数量的单元测试达到某种限制,这将使你确信它将适用于所有必要的情况。然而,在涉及更多算法的更复杂场景中,这成为YAGNI的益处的有用研究。如果要求声明您需要能够将记录A保存到数据库中,并且省略了保存记录B的能力,那么您必须得出结论“您不需要”保存记录B的能力,直到满足要求为止。来自那个状态。如果你在知道需要之前实现了保存记录B的能力,那么如果事实证明你永远不需要那么你就浪费了时间和精力来建立系统;你有没有商业目的的代码,无论如何仍然“破坏”你的系统,因此需要维护。

即使在更简单的情况下,如果您的代码超出了您“知道”太轻或特定的要求,您的编码可能会超出您的需要。假设您正在为字符串代码实现某种解析器。要求声明字符串代码“AA”= 1,“AB”= 2,这是要求的限制。但是,您知道此系统中的完整代码库包括其他20个代码库,因此您包含解析完整库的逻辑和测试。你回到客户端,期待你的时间和材料付款,客户说:“我们没有要求;我们只使用我们在测试中指定的两个代码,所以我们不付钱给你额外的工作”。他们是完全正确的;你在技术上试图通过收取他们没有要求而且不需要的代码来欺骗他们。