TDD如何使重构更容易?

我听说使用TDD开发的项目更容易重构,因为实践产生了一套全面的单元测试,如果任何更改破坏了代码,这将会(希望)失败。然而,我所看到的所有例子都处理重构实现 – 例如,用更高效的算法改变算法。

我发现重构架构在设计仍在制定的早期阶段是更常见的。接口改变,新类加入&删除,甚至一个函数的行为可能会有轻微的变化(我认为我需要它做到这一点,但它实际上需要这样做),等等…但如果每个测试用例是紧密耦合到这些不稳定的类,不会你必须不断地重写你的测试用例每次你改变一个设计?

在TDD的什么情况下,是否可以更改和删除测试用例?如何确保改变测试用例不会破坏测试用例?另外,似乎不得不同步一个全面的测试套件与不断变化的代码将是一个痛苦。我知道单元测试套件在维护期间可以帮助非常大,一旦软件构建,稳定和正常运行,但是在游戏的后期,TDD也应该在早期帮助。

最后,一本关于TDD和/或重构的好书能解决这些问题吗?如果是这样,你会推荐什么?

Plus it seems that having to
synchronize a comprehensive test suite
with constantly changing code would be
a pain. I understand that the unit
test suite could help tremendously
during maintenance,once the software
is built,stable,and functioning,but
that’s late in the game wheras TDD is
supposed to help early on as well.

我确实同意,在发生主要架构变化时,在这些早期变化时可以感觉到具有单元测试套件的开销,但是我认为,单元测试的好处远远超过这个缺点。我认为问题常常是一个精神问题 – 我们倾向于认为我们的单元测试是代码库的第二类公民,我们不得不混淆他们。但是随着时间的推移,我已经依赖于他们并欣赏它们的有用性,我已经认为它们与代码库的任何其他部分一样重要,不逊于维护和工作。

主要的架构“变化”是否真的只是重构?如果你只是重构,但是显着,测试开始失败,这可能会告诉你,你不经意地改变了某处的功能。这是什么单位测试应该帮助你抓住。如果你正在对功能和架构同时进行彻底的更改,你可能想考虑放慢和进入红/绿/重构槽:没有新的(或改变的)功能,无额外的测试,没有更改功能(和中断测试)。

更新(基于评论):

@Cybis提出了一个有趣的反对我的说法,重构不应该打破测试,因为重构不应该改变行为。他的反对意见是重构确实改变了API,因此测试“break”。

首先,我鼓励任何人访问重构的规范参考:Martin Fowler’s bliki.刚刚我检查了它,一些事情跳出我:

> Is changing an interface
refactoring?
Martin指的是
重构为
“行为保持”的变化,这
意味着当接口/ API改变时
然后所有的呼叫者
接口/ API也必须更改。
包括测试,我说。
>这并不意味着行为已经改变。同样,福勒强调他的
重构的定义是
更改是行为
保存。

鉴于此,如果一个或多个测试在重构期间必须改变,我不认为这是“中断”测试。它只是重构的一部分,保留整个代码库的行为。我认为在必须更改的测试和代码库的任何其他部分必须作为重构的一部分进行更改之间没有差别。 (这回到我之前说的考虑测试是代码基础的一流公民。)

此外,我希望测试,即使是修改的测试,一旦重构完成后继续传递。无论那个测试是测试(可能是测试中的断言)在重构完成后仍然是有效的。否则,这是一个红色的标志,行为改变/回归在重构期间不知何故。

也许这个声明听起来像废话,但想想:我们不考虑在生产代码库中移动代码块,期望他们继续在他们的新上下文中工作(新类,新的方法签名,无论什么)。我对测试有同样的感觉:也许一个重构改变了一个测试必须调用的API,或者一个测试必须使用的类,但是最终测试的点不应该因为重构而改变。

(我唯一能想到的例外是测试在重构过程中可能需要改变的低级实现细节,例如用ArrayList或其他东西替换LinkedList,但在这种情况下,可以认为测试是过度测试,太僵硬和脆弱。)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结