Alexander Day Chaffee(alex@jguru.com),顾问,Purple Technology William Pietri(william@scissor.com),顾问,Scissor
模拟对象(Mock object)是为起中介者作用的对象编写单元测试的有用方法。测试对象调用模拟域对象(它只断言以正确的次序用期望的参数调用了正确的方法),而不是调用实际域对象。然而,当测试对象必须创建域对象时,我们面临一个问题。测试对象如何知道创建模拟域对象,而不是创建实际域对象呢?在本文中,软件顾问 Alexander Day Chaffee 和 William Pietri 将演示一种重构技术,该技术根据工厂方法设计模式来创建模拟对象。 单元测试已作为软件开发的“最佳实践”被普遍接受。当编写对象时,还必须提供一个自动化测试类,该类包含测试该对象性能的方法、用各种参数调用其各种公用(public)方法并确保返回值是正确的。
在 Nicholas Lesiecki 的文章“Test flexibly with aspectJ and mock objects”中,他指出重构不一定总是合意的,也不一定总是产生更清楚或更轻易理解的代码。在许多情况下,更改方法签名以使合作者成为参数将会在方法的原始调用者内部产生混淆的、未经试验的代码混乱。
许多语言对于“工厂”这一概念都附有一些约定,它们会使您误入歧途。例如,在 Java 语言中,工厂通常作为静态方法实现;在这种情况下,这是不合适的。 请记住,本练习的宗旨是使对象更易于测试。通常,用于可测性的设计可以将对象的 API 推向一种更清楚更模块化的状态。但它会走得太远。测试驱动的设计更改不应该污染原始对象的公用接口。
在 ATM 示例中,对于产品代码,AtmGui 对象始终只产生一种类型的 Transaction 对象(实际类型)。测试代码希望它产生另一种类型的对象(模拟对象)。但强迫公用 API 适应工厂对象或抽象工厂(只因为测试代码要求它这样)是错误的设计。假如产品代码无需实例化该合作者的多个类型,那么添加该功能将使最终的设计不必要地变得难于理解。
参考资料
由 Tim Mackinnon、Steve Freeman 和 Philip Craig 合著的文章“Endo-Testing: Unit Testing with Mock Objects”介绍了术语模拟对象。
Mock Objects Project 是支持模拟对象实现的框架。
工厂方法和抽象工厂设计模式的来源是由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides(也称为四人组(Gang of Four))合著的 Design Patterns: Elements of Reusable Object-Oriented Software(Addison-Wesley,1997 年)。
William Pietri 的父亲是一位系统分析师和企业家,William 在十三岁时就开始利用计算机赚取午餐费。从那以后,他几乎从事过技术领域的各个方面,从技术支持到系统治理到软件工程到用户界面设计。他是 Scissor(技术咨询公司)的创办人。可以通过 william@scissor.com 与 William 联系。