另外,似乎必须将全面的测试套件与不断变化的代码同步会很痛苦。我知道单元测试套件可以在维护期间提供巨大帮助,一旦软件构建、稳定和运行,但这是在游戏后期,而 TDD 也应该在早期提供帮助。
我确实同意在这些早期变化中可以感受到单元测试套件的开销,当主要的架构变化发生时,但我认为单元测试的好处远远超过这个缺点。我经常认为问题出在心理问题上——我们倾向于将单元测试视为代码库的二等公民,我们讨厌不得不与它们打交道。但随着时间的推移,随着我开始依赖它们并欣赏它们的有用性,我开始认为它们与代码库的任何其他部分一样重要,也同样值得维护和工作。
主要的架构“变化”真的只是重构吗?如果您只是重构,无论多么显着,并且测试开始失败,那可能会告诉您您无意中更改了某处的功能。这正是单元测试应该帮助你抓住的。如果您同时对功能和架构进行彻底的更改,您可能需要考虑放慢速度并进入红/绿/重构槽:没有新的(或更改的)功能没有额外的测试,也没有更改重构时的功能(和中断测试)。
更新(基于评论):
@Cybis 对我的主张提出了一个有趣的反对意见,即重构不应该破坏测试,因为重构不应该改变行为。他的反对意见是重构确实会改变 API,因此会测试“中断”。
首先,我鼓励任何人访问有关重构的规范参考:Martin Fowler 的 bliki。刚才我回顾了它,有几件事突然出现在我身上:
- 改变接口重构? Martin 将重构称为“行为保持”更改,这意味着当接口/API 更改时,该接口/API 的所有调用者也必须更改。我说,包括测试。
- 这并不意味着行为已经改变。Fowler 再次强调,他对重构的定义是更改是
保持行为的。
鉴于此,如果一个或多个测试在重构期间必须更改,我不认为这是“破坏”测试。它只是重构的一部分,保留了整个代码库的行为。我认为必须更改的测试与作为重构的一部分必须更改的代码库的任何其他部分之间没有区别。(这可以追溯到我之前所说的将测试视为代码库的一等公民。)
此外,我希望测试,甚至是修改后的测试,在重构完成后继续通过。无论该测试正在测试什么(可能是该测试中的断言)在重构完成后都应该仍然有效。否则,这是一个危险信号,在重构过程中行为以某种方式改变/退化。
也许这种说法听起来像是胡说八道,但仔细想想:我们对在生产代码库中移动代码块并期望它们继续在新的上下文中工作(新类、新方法签名等)没有任何想法。我对测试也有同样的感觉:也许重构改变了测试必须调用的 API,或者测试必须使用的类,但最终测试点不应该因为重构而改变。
(我能想到的唯一例外是测试您可能希望在重构期间更改的低级实现细节的测试,例如用 ArrayList 或其他东西替换 LinkedList。但在这种情况下,人们可能会争辩说测试过度测试并且过于僵化和脆弱。)