[转载]测试驱动开发之模拟对象(概念篇)

1、前言

在测试驱动开发过程当中咱们最关注的是以下一些内容:
目标专注的测试:理想状况下每一个测试只有一条断言;
彼此独立的测试:对于每一个测试都存在预设环境(Fixture)的创建和清除,以便让测试可以以任意顺序执行;
运行速度的测试:你想可以频繁地运行这些测试。

以 上目标天然致使一种潜在的矛盾。由于简短而专注的测试就意味着你将会有许多这样的测试,从而保证每一个都很是简短而专注。而要想使这些测试彼此独立,显然就 须要针对每一个测试都有整洁的预设环境。此外,上面咱们最后一个目标便是:但愿测试速度执行神速......尽量地快......以便咱们至关频繁地执行 它们(由于咱们如今在作测试编程,而仍是根本目标--最终的目标编程)。
对于中小型目标来讲,以上预设环境的创建彷佛不成问题;可是,在开发大型项目时,若是测试的预设环境变得至关复杂并且构造或清除起来很是困难时,咱们该怎么办呢?
针 对以上问题,有些开发人员可能想到建立大量的预设环境代码,而有些开发人员所在的工做环境多是一种大型的、复杂的系统--这种环境多是数据库、工做流 系统或者是某种你正在为其开发扩展模块的系统。为此,你的预设环境代码须要使系统进入某种特定的状态,以便按照测试所须要的方式进行响应,这种工做不大可 能很快就完成。
若是存在以上难以处理的测试资源的话,咱们如何在专注性、独立性和速度这三个目标之间进行权衡呢?数据库

实践证实:模拟对象(即Mocks)是一种极其有效可靠的解决方案。当咱们很难或不可能为某种难以处理的资源建立须要的状态或访问那种资源受到限制时,就能够充分发挥模拟对象的做用。其实,模拟对象还有其余重要做用。在本篇中,咱们将详细探讨什么是模拟对象及其可能发挥的有关做用。编程

2、什么是模拟对象(Mocks)

根据测试驱动开发权威人士的解释,模拟对象(即Mocks)用来取代真实对象的位置,用于测试一些与真实对象进行交互可依赖于真实对象的功能。模拟对象(即Mocks)背后的基本思想是建立轻量级的、可控制的对象来代替为了编写测试而须要使用的对象。此外,模拟对象(即Mocks)还可以让你指定和测试你的代码与模拟对象(即Mocks)自己之间的交互。框架

3、模拟对象的用途总结

除了能够保持测试预设环境的轻量级,以即可以快速地建立和清除外,使用模拟对象还有其余一些好处。咱们使用模拟对象的缘由至关之多。具体说来,有如下诸多理由要求咱们采用模拟对象的辅助解决方案:工具

(1)有助于保持设计的松耦合性

采用模拟对象有助于咱们强化以接口为中心的设计。针对模拟对象进行编程能够消除依赖对象内部实现的可能性。单元测试

(2)检查你的代码使用另外一个对象是否得当

经过在模拟对象中设按期望值(Expectation),咱们能够验证编写的代码是否恰当地使用了模拟的接口。测试

(3)由内而外地利用测试来驱动代码的开发

经过在模拟对象中设定返回值,能够为咱们正在开发的代码提供特定的信息,而后测试最终的行为是否正确。网站

(4)可让测试运行得更快

经过模拟诸如通讯或数据库这样的子系统,咱们可以避免设置和清除链接等资源所带来的开销。this

(5)可让咱们更容易地开发与硬件设备、远程系统以及其余一些难以处理的资源进行交互的代码

若是咱们所编写的代码须要与一些难以处理的资源进行交互的话,那么咱们能够建立一个代理层来隔离实际的资源。这样,咱们就可以使用代理层的模拟对象,无需访问实际的设备或系统就能够开发代码。编码

(6)推迟必需的类实现

针对那些还没有编写出来的可是咱们正在开发的代码而又须要与之进行交互的类来讲,咱们可使用它们的模拟对象。这样,咱们就可以推迟实现这些类,以便集中精 力处理这些类与咱们正在编写的代码之间的接口。从而,咱们能够针对具体实现做出决定,直到咱们了解了更多的信息之后再做决定。若是你的测试所须要的只是模 拟行为,那么使用模拟对象就足够了。spa

(7)可让咱们在进行测试驱动开发时把要开发的部件与系统的其余部分分隔开来

经过模拟咱们正在编写的代码必需要与之交互的部件,咱们能够单独专一于这个部件的开发。这样以来,咱们的开发速度就会更快,由于咱们正在开发的部件与其余部件之间的复杂的交互彻底处于咱们的控制之下。

(8)提倡基于接口的设计

注意,当你使用以接口为主(或指导思想)的编程理念时才易于使用模拟对象。

(9)鼓励使用组合而不是继承进行程序设计

在OOP设计思想影响下,大多数人总会过分地使用继承技术。结果是,基于继承层次而构建出一种一体化的功能。一个类永远是它所继承的那种样子。因而致使: 模拟位于继承层次中的类的任何一个方面都变得至关困难,由于这个类还要承载它所继承的全部的负担。这种想要对特定方面(例如持久性存储)实施模拟的愿望使 咱们倾向于编写出相对较小的类,这些类经过与其余类的相互协做而可以实现丰富的功能。这种类的不一样实现,包括模拟对象在内,都可以很容易地相互替换。

(10)改进接口

使用你最终须要实现的类的模拟,可让你早早地有机会思考接口并改进之。这在使用测试优先的设计时尤为如此。你不得不从将要使用这个接口的类的角度来考虑这个接口--由于你开始编写的是一个使用这个接口的真实的测试程序。

(11)用来测试非同寻常的、不大可能出现的例外状况

你能够建立一个模拟对象,让它返回在一般状况下不会返回的返回值,或是建立一个能够在须要的时候抛出异常的模拟对象。这样可让你很容易地对异常处理进行测试。总之,出现测试的目的,你彻底能够编写出一个可以模拟任何难以发生的状况下模拟。

4、经常使用模拟框架简介

最开始,Mock Object是彻底由测试者本身手工撰写的。这样,无可避免的会带来编写测试用例效率低下和测试用例编写困难的弊病,甚至可能会影响XP实践者“测试先行”的激情。此时,各类各样帮助建立Mock Object的工具就应运而生了。
目前,在Java阵营中主要的Mock测试工具备JMock,MockCreator,MockRunner,EasyMock,MockMaker等,在微软的.Net阵营中主要是NMock,.NetMock,Rhino Mocks和Moq等。

(1)MockObjects

咱们可使用四种方式来利用MockObjects编写测试用例:
    一、基于MockObjects的框架编写本身的Mock Object实现并与其余人分享;
    二、直接使用MockObjects提供的Mock Object进行测试;
    三、使用其中包含的DynaMock模块快速获取Mock Object实例;
    四、经过它提供的Helpers对象帮助咱们快速构建测试环境。

(2)MockMaker

主页为http://mockmaker.sourceforge.net/。目前这个框架彷佛发展缓慢,这从它针对的应用平台为Windows 2000, Linux, Java 1.2 & Java 1.4这一点能够看得出。

(3)MockCreator

JAVA平台的模拟对话框架,开源网址为http://mockcreator.sourceforge.net/,最新下载支持为MockCreator-2006-09-07。

(4)EasyMock 

手动的构造 Mock 对象会给开发人员带来额外的编码量,并且这些为建立 Mock 对象而编写的代码颇有可能引入错误。目前,有许多开源项目对动态构建 Mock 对象提供了支持,这些项目可以根据现有的接口或类动态生成,这样不只能避免额外的编码工做,同时也下降了引入错误的可能。

EasyMock 是一套用于经过简单的方法对于给定的接口生成 Mock 对象的类库。它提供对接口的模拟,可以经过录制、回放、检查三步来完成大致的测试过程,能够验证方法的调用种类、次数、顺序,能够令 Mock 对象返回指定的值或抛出指定异常。经过 EasyMock,咱们能够方便的构造 Mock 对象从而使单元测试顺利进行。

(5)NMock 

NMock 是一个基于动态代理的模拟工具,用于 C# 开发。NMock使用了代理模式,这容许类实现一个接口并以代理的方式将其它对象的调用转向。NMock生成的模拟是经过在运行时使用动态代理来实现的, 这容许模拟对象动态的定义,并不须要添加任何附加的类。一般,一个模拟的实现基于被依赖的接口而建立;NMock支持对接口和类的模拟,另外它还支持属性 模拟。

(6)Rhino Mocks和Moq

Rhino Mocks和Moq是.NET平台下的两个新建立的优秀的模拟对象框架,有关于此两者的对比,读者能够参考中文博客“比较Moq和Rhino Mocks两个测试框架”,URL为:http://blog.joycode.com/haacked/archive/2008/03/24/115023.aspx。从许多的博客文章中能够看到,这两个框架在.NET平台下获得了普遍应用,颇受好评。

(7)JMock

JMock利用模拟对象思想来对Java代码进行测试。归纳来看,JMock具备如下特色:容易扩展,让你快速简单地定义模拟对象,所以没必要打破程序间的关联,让你定义灵活的超越对象之间交互做用而带来测试局限,减小你测试地脆弱性。

篇幅所限,在此仅仅列举上面几种常见的模拟对象框架,并且仅仅做了简单介绍。至于各类框架的具体特征与相应示例展现,请参考各框架的官方网站。

    5、小结

从简短的文章介绍,能够看出模拟对象确实可以协助咱们实如今本文开始所关注的三个目标,即:目标专注的测试;彼此独立的测试和快速的测试。到目前为止,模拟对象仍然是一种至关年轻的概念,有关的新工具和新技术将不断被开发出来。针对.NET 2.0框架的Moq就是例证之一。

切记:个别状况下,可能还须要经过手工方式建立模拟类(这些可能要用到MockObjects这样的框架)。尽管如此,你仍然可以经过使用像本文所给出的模拟框架这样的工具来建立模拟类的框架代码--你能够基于它们所产生的框架代码进一步增长定制的行为。

最后还要牢记:模拟对象是一种测试驱动开发的很是好的技术,由于有些状况下它实在很是有用,可是不要过分使用或过分依赖于它。它仅仅是软件开发中锦囊中的妙计之一,具体的应用则真正环境而定。

原文连接:http://space.itpub.net/14518332/viewspace-430102

相关文章
相关标签/搜索