试图对TDD的好处充满信心

Rei*_*aka 11 testing tdd unit-testing functional-programming

我刚买了亚马逊的单元测试艺术.我非常认真地了解TDD,所以请放心,这是一个真正的问题.

但我觉得我总是在寻找放弃它的理由.

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

1. TDD减少错误

这篇经常被引用的博客文章说,单元测试是设计工具而不是用于捕获错误:

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

...

TDD是一种以交互方式设计软件组件("单元")的强大方式,以便通过单元测试指定其行为.就这样!

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

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

2. TDD作为设计范例

这可能是最重要的一个.TDD是一种设计范例,可以帮助您(或强迫您)使您的代码更具可组合性.

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

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

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

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

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

3. TDD作为文件

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

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

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

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

4.用于回归测试的TDD

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

关于该主题还可能需要注意的是,大部分代码在相当长的时间内保持相同的可能性很大.因此,无论何时更改代码,保留旧代码并将其结果与新函数进行比较,根据需要编写单元测试是不是更有意义?

Yis*_*hai 5

In terms of design, one major benifit of TDD you are not seeing is that it drives design to be just enough. You know what they say the engineer sees the glass as twice as large as it should be. Overdesign in software can be a big problem. I find that 90+% of the time TDD forced out the right ballance of abstraction to support later extension of the code. TDD isn't magic, it takes the programmer behind it to do that as well, but it is an important part of the toolkit.

I think that there is too much TDD in isolation in your list. What about refactoring? I think one of the prime benifits of the test is that it locks down behavior, so that when you refactor you can be confident that you haven't changed anything, which in turn can make you confident about refactoring. And there is nothing like a design which is born from experience rather than a whiteboard (although high-level whiteboard design is still very important).

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

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

  • 关于重构,你制作软件的组合方式并不重要,如果你想重构代码的内部结构,你会害怕没有安全的网络.除非你异常善良或异常愚蠢. (2认同)

Bob*_*rbo 4

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

此外,它还能将您置于用户的脑海中。你必须思考“那么用户需要我的方法做什么”或者其他什么,而不是“我希望我的方法已经实现了它应该做的事情”。这样,也可能有助于减少 bug。