重构由许多小的技术性步骤组成。这些步骤统称为 技巧。如果您象按照食谱那样严格遵循这些技术, 那么您在学习重构时应该没有太大的麻烦。
- 标识创建或获取合作者的代码的所有出现。
- 将
抽取方法重构应用于这个创建代码,创建工厂方法(在 Fowler 书籍的第 110 页中讨论;有关更多信息,请参阅
参考资料一节)。
- 确保目标对象及其子类可以访问工厂方法。(在 Java 语言中,使用
protected
关键字)。
- 在测试代码中,创建模仿对象且实现与合作者相同的接口。
- 在测试代码中,创建扩展(专用于)目标对象的特殊化对象。
- 在特殊化对象中,覆盖创建方法以返回为测试提供的模仿对象。
- 可选的:创建单元测试以确保原始目标对象的工厂方法仍返回正确的非模仿对象。
设想您正在编写用于银行自动柜员机(Automatic Teller Machine)的测试。其中一个测试可能类似于清单 2:
清单 2. 初始单元测试,在模仿对象引入之前
public void testCheckingWithdrawal() { |
另外,
AtmGui
类内部的匹配代码可能类似于清单 3:
清单 3. 产品代码,在重构之前
private Status doWithdrawal(Account account, float amount) { |
该方法将起作用,遗憾的是,它有一个副作用:支票帐户余额比测试开始时少,这使得其它测试变得更困难。 有一些解决这种困难的方法,但它们都会增加测试的复杂性。 更糟的是,该方法还需要对管理货币的系统进行三次往返。
要修正这个问题,第一步是重构
AtmGui
以允许我们用模仿事务替换实际事务,
如清单 4 中所示(比较
粗体的源代码以查看我们正在更改什么):
清单 4. 重构 AtmGui
private Status doWithdrawal(Account account, float amount) { |
后退到测试类内部,我们将
MockTransaction
类定义为成员类,如清单 5 中所示:
清单 5. 将 MockTransaction 定义为成员类
private MockTransaction extends Transaction { |
最后,我们可以重写测试,以便被测试的对象使用
MockTransaction
类,而不是使用实际类,如清单 6 中所示:
文章来源于领测软件测试网 https://www.ltesting.net/