试图对TDD的好处充满信心

时间:2010-07-18 02:37:22

标签: unit-testing testing functional-programming tdd

我刚刚从亚马逊购买了The Art of Unit Testing。我非常认真地了解TDD,所以请放心,这是一个真正的问题。

但我觉得我一直在寻找放弃它的理由。

我将在这里扮演魔鬼的拥护者并试图击败TDD的所谓好处,希望有人可以证明我是错的,并帮助我对其美德更有信心。我想我错过了一些东西,但我无法弄清楚是什么。

1。 TDD减少错误

这个often-cited blog post表示单元测试是设计工具而不是用于捕获错误:

  

根据我的经验,单元测试不是   找到错误或检测回归的有效方法。

     

...

     TDD是一种强大的设计方式   软件组件(“单位”)   交互式地使他们的行为   通过单元测试指定。   这就是全部!

有道理。边缘情况仍然总是在那里,而你只会找到表面上的错误 - 无论如何,只要你运行你的应用程序就会找到它们。在构建了大量软件之后,您仍需要进行适当的集成测试。

公平地说,减少错误并不是TDD应该提供的唯一帮助。

2。 TDD作为设计范例

这可能是最重要的一个。 TDD是一种设计范例,可以帮助您(或强迫您)使您的代码更加composable

但可组合性是多重可实现的质量;例如,函数式编程风格使代码也可以组合。当然,完全以功能风格编写大型应用程序很困难,但是为了保持可组合性,您可以遵循某些折衷模式。

如果您从高度模块化的功能设计开始,然后根据需要小心地将状态和IO添加到您的代码中,您将得到TDD鼓励的相同模式。

例如,为了在数据库上执行业务逻辑,IO代码可以在一个函数中被隔离,该函数执行访问数据库的“monadic”任务并将其作为参数传递给负责业务逻辑的函数。这将是实现它的功能性方法。

当然,这有点笨重,所以相反,我们可以将数据库IO代码的一个子集放入一个类中,并将其提供给包含相关业务逻辑的对象。这是完全相同的事情,是功能性做事方式的改编,它被称为存储库模式。

我知道这可能会给我带来非常糟糕的鞭挞,但有时候,我不禁觉得TDD只是弥补了OOP可以鼓励的一些坏习惯 - 可以避免的从功能风格中汲取灵感。

第3。 TDD作为文档

据说TDD可以作为文档,但它只作为同行的文档;消费者仍然需要文本文档。

当然,TDD方法可以作为示例代码的基础,但是测试通常包含一定程度的模拟,这些模拟不应该在示例代码中,并且通常是非常人为的,因此可以对它们进行相等的评估。预期的结果。

一个好的单元测试将在其方法签名中描述正在验证的确切行为,并且测试将不再验证该行为。

所以,我会说,你的时间可能会更好地用于完善你的文档。哎呀,为什么不先彻底完成文档,并称之为文档驱动设计?

4。用于回归测试的TDD

上面的帖子中提到,TDD对于检测回归并不太有用。当然,这是因为当您更改某些代码时,非显而易见的边缘情况总会陷入困境。

在该主题上可能还需要注意的是,很长一段时间大多数代码将保持相同的可能性很大。那么,每当代码改变时,根据需要编写单元测试,保留旧代码并将其结果与新函数进行比较,是不是更有意义?

6 个答案:

答案 0 :(得分:5)

在设计方面,你没有看到TDD的一个主要优点是它驱动设计就足够了。你知道他们说工程师看到的玻璃是它应该的两倍大。软件中的过度设计可能是一个大问题。我发现90%以上的时间TDD强制推出正确的抽象平衡,以支持以后扩展代码。 TDD并不神奇,它背后的程序员也可以做到这一点,但它是工具包的重要组成部分。

我认为列表中的TDD太多了。重构怎么样?我认为测试的一个主要优点是它可以锁定行为,因此当你重构时,你可以确信你没有改变任何东西,这反过来可以让你对重构充满信心。没有什么比设计出生的经验而不是白板(尽管高级白板设计仍然非常重要)。

另外,你写道:“那么,每当代码改变时,根据需要编写单元测试,保留旧代码并将其结果与新函数进行比较,是不是更有意义?”在没有单元测试的情况下编写的代码通常是不可测试的,特别是如果它与外部服务(如数据库,事务管理器,GUI工具包或Web服务)交互时。稍后添加它们就不会发生。

我认为Bob Martin说得最好,TDD就是编写Double Entry对Accounting的编程。它可以防止某类错误。它不会阻止所有问题,但确实如果你的程序想要添加两加二,它就不会减去它们。基本行为很重要,当它出错时,您可以花很多时间来了解调试器。

答案 1 :(得分:3)

我相信TDD的好处在于你实际上编写了测试,因为当它们是你必须实现的目标时更有趣,(创建通过测试的代码),而不是之后你必须做的苦差事。

此外,它让您了解用户的想法。你必须考虑“那么用户需要我的方法做什么”或者其他什么,而不是“我希望我的方法已经实现了它应该做的”。通过这种方式,它也可以帮助减少错误。

答案 2 :(得分:2)

TDD不是一种方法论,它是一种心态。

TDD减少错误:随着您的代码库开始增长,在每个签入到源代码管理上运行所有测试非常重要。当您在团队中有新成员时,这一点的好处就变得很明显。

TDD作为设计范例:测试是代码的第一批用户。最初,使用测试来驱动您的设计非常困难。但是,一旦你对它感到满意,你就会意识到测试代码实际上可以帮助你决定你的设计。这自然具有一些TDD经验。例如,使用TDD,您希望在界面中包装对服务的访问。这允许你模拟。但是,最重要的是它是正确的设计方式。

TDD作为文档该文档适用于代码开发人员使用的代码文档。开发人员发现很容易阅读编写良好的单元测试,而不是文档的页面和页面。

答案 3 :(得分:1)

我只想强调:
TDD测试不是单元测试

“单元测试的目的是单独测试一个代码单元。”
“与单元测试不同,TDD测试可能会一次测试多个代码单元。” TDD测试是更多的交互测试....

来自Stephen Walter非常好的博文TDD Tests are not Unit Tests

答案 4 :(得分:1)

在Javascript或任何必须在浏览器等多个古怪环境中运行的语言中,单元测试是告诉 Internet Effing Explorer搞砸了修复内容的好方法。

至少它比锤击F5并使用console.log()甚至警报更好。

但是,我认为这应该主要用于中间件或复杂的RIA - 因为TDD用户界面几乎不可能具有很少的业务逻辑。

如果你写下一个jQuery,单元测试将是你的朋友! :)

哦,让我们不要忘记像JSTestDriver这样的js的好工具!

答案 5 :(得分:0)

TDD还为您提供了自动化单元测试完全涵盖的代码。这只是因为在完成失败的单元测试通过之前,不会编写任何代码。