单元测试已作为软件开发的“最佳实践”被普遍接受。当编写对象时,还必须提供一个自动化测试类,该类包含测试该对象性能的方法、用各种参数调用其各种公用(public)方法并确保返回值是正确的。
当您正在处理简单数据或服务对象时,编写单元测试很简单。然而,许多对象依赖基础结构的其它对象或层。当开始测试这些对象时,实例化这些合作者(collaborator)通常是昂贵的、不切实际的或效率低的。
例如,要单元测试一个使用数据库的对象,安装、配置和发送本地数据库副本、运行测试然后再卸装本地数据库可能很麻烦。模仿对象提供了解决这一困难的方法。模仿对象符合实际对象的接口,但只要有足够的代码来“欺骗”测试对象并跟踪其行为。例如,虽然某一特定单元测试的数据库连接始终返回相同的硬连接结果,但可能会记录查询。只要正在被测试的类的行为如所期望的那样,它将不会注意到差异,而单元测试会检查是否发出了正确的查询。
夹在中间的模仿
使用模仿对象进行测试的常用编码样式是:
创建模仿对象的实例 设置模仿对象中的状态和期望值 将模仿对象作为参数来调用域代码 验证模仿对象中的一致性虽然这种模式对于许多情况都非常有效,但模仿对象有时不能被传递到正在测试的对象。而设计该对象是为了创建、查找或获得其合作者。
例如,测试对象可能需要获得对 Enterprise JavaBean(EJB)组件或远程对象的引用。或者,测试对象会使用具有副作用的对象,如删除文件的File对象,而在单元测试中不希望有这些副作用。
根据常识,我们知道这种情形下可以尝试重构对象,使之更便于测试。例如,可以更改方法签名,以便传入合作者对象。
在 Nicholas Lesiecki 的文章“ Test flexibly with AspectJ and mock objects”中,他指出重构不一定总是合意的,也不一定总是产生更清晰或更容易理解的代码。在许多情况下,更改方法签名以使合作者成为参数将会在方法的原始调用者内部产生混淆的、未经试验的代码混乱。
问题的关键是该对象“在里面”获得这些对象。任何解决方案都必须应用于这个创建代码的所有出现。为了解决这个问题,Lesiecki 使用了查找方式或创建方式。在这个解决方案中,执行查找的代码被返回模仿对象的代码自动替换。
因为 AspectJ 对于某些情况不是选项,所以我们在本文中提供了一个替代方法。因为在根本上这是重构,所以我们将遵循 Martin Fowler 在他创新的书籍“Refactoring: Improving the Design of Existing Code”(请参阅 参考资料)中建立的表达约定。(我们的代码基于 JUnit ― 编程的最流行的单元测试框架,尽管它决不是 JUnit 特定的。)
重构:抽取和覆盖工厂方法
重构是一种代码更改,它使原始功能保持不变,但更改代码设计,使它变得更清晰、更有效且更易于测试。本节将循序渐进地描述“抽取”和“覆盖”工厂方法重构。
问题:正在测试的对象创建了合作者对象。必须用模仿对象替换这个合作者。
文章来源于领测软件测试网 https://www.ltesting.net/