单元测试—使用模拟对象做交互测试

最近在看.net单元测试艺术,我也喜欢单元测试,这里写一下如何在测试中使用模拟对象。

  开发的过程中,我们都会遇到对象间的依赖,比如依赖数据库或文件,这时,我们需要使用模拟对象,来进行测试,我们可以手写模拟对象,当然也可以使用模拟框架。

  假如有这样的一个需求,当用户登陆时,我需要对用户名和密码进行验证,然后再将用户名写入日志中。


public class MyLogin

{

public ILog Log { get; set; }

public bool Valid(string userName, string passWord)

{

var isValid = userName == "admin" && passWord == "123456";

Log.Write(userName);

return isValid;

}

}

public interface ILog

{

void Write(string message);

}

  上面的代码在验证完登陆信息后,需要向日志中写入用户名,由于写入日志可能依赖于文件或数据库,我们可能很难进行测试,所以,这里使用模拟对象进行测试。手写模拟对象,代码如下:


public class MyLoginTest

{

[Test]

public void Vaild_Test()

{

MyLogin login = new MyLogin();

var log = new TestLog();

login.Log = log;

var userNmae = "admin";

var passWord = "123456";

var isLogin = login.Valid(userNmae, passWord);

Assert.AreEqual(isLogin, true);

Assert.AreEqual(log.Message, userNmae);

}

}

public class TestLog : ILog

{

public string Message;

public void Write(string message)

{

this.Message = message;

}

}

  这里我们定义了一个对象TestLog对象,该对象就是一个模拟对像,继承了ILog接口。该测试中,一共进行了两项测试。一项是:验证用户名和密码是否输入正确。另一项是:验证用户写入日志的信息是否正确(比如应该写入用户名,结果把密码写入了日志,测试会无法通过)。

  这里我们区分一下模拟对象与桩对象。上一节中,我们讲过桩对象的定义,那么模拟对象与桩对象是什么关系呢?

  模拟对象与桩对象在写法上区别很小,关键在于模拟对象需要进行断言,也就是说模拟对象可以导致测试失败。桩对象只是为了方便测试所定义的一个对象,不需要进行断言,所以,桩对象永远不会导致测试失败。

  上面的测试中,如果我们去掉最后一行代码,即我们不进行写入日志的断言,则该对象就是一个桩对象。

  Assert.AreEqual(log.Message, userNmae);

  上面的模拟对象是我们自己写的,自己写模拟对象比较费时,我们可以使用模拟框架进行编写。这里我使用了Rhino Mocks框架。如果要执行下面的代码,需要下载Rhino.Mocks.dll文件,然后直接引用即可。

  测试框架这里我选用了NUnit框架。测试代码如下:


[TestFixture]

public class MyLoginTest

{

[Test]

public void Mock_Vaild_Test()

{

MockRepository mock = new MockRepository();

var log = mock.DynamicMock<ILog>();

var userName = "admin";

var passWord = "123456";

using (mock.Record())

{

log.Write(userName);

}

MyLogin login = new MyLogin();

login.Log = log;

var isLogin = login.Valid(userName, passWord);

Assert.AreEqual(isLogin, true);

mock.VerifyAll();

}

  这里我没有编写一个类去继承ILog接口,而是通过模拟框架,动态生成了一个ILog对象。代码是这句:

  MockRepository mock = new MockRepository();

  var log = mock.DynamicMock<ILog>();

  这里便生成了Log对象。通过录制-回放的模式进行模拟对象测试,首先需要定义我们的期望行为,最后验证实际行为与期望行为是否一致。这里,需要录制我们期望行为,代码如下:


using (mock.Record())

{

log.Write(userName);

}

  这里我们期望向日志中写入用户名。再通过回放来进行验证,代码如下:

  mock.VerifyAll();

  该方法会验证,期望向日志中写入的信息与实际向日志中写入的信息是否一致,如果不一致,测试失败。

  这里我们便完成了使用模拟框架进行单元测试。如果我们不需要测试日志写入方法,则把模拟对象换成桩对象就可以了,生成桩对象的方法如下:

  MockRepository mock = new MockRepository();

  var log = mock.Stub<ILog>();

  把回放的方法(mock.VerifyAll())去掉,就完成了模拟对象向桩对象的转变。注意,这里录制的代码还是需要的。

  总结:编写模拟对象和桩对象是非常有意义的,使用框架可以帮助我们简化单元测试。一般情况下,一个测试中,可以有多个桩对象,但最好只有一个模拟对象。模拟对象太多,证明一个测试方法做了太多项测试,不利于维护测试代码,一旦代码变改,很容易使单元测试失败。

  下一节,写一下测试框架的一些常用功能,如:如何模拟异常、如何模拟返回值等。。。

最新内容请见作者的GitHub页:http://qaseven.github.io/

时间: 2024-09-26 01:03:30

单元测试—使用模拟对象做交互测试的相关文章

《有效的单元测试》一3.2 测试替身的类型

3.2 测试替身的类型 你见过了使用测试替身的各种原因,我们也暗示了有多种测试替身可供选择.我们来仔细看看那些类型吧.图3.3展示了这把大伞下的四种对象. 既然我们已经制定了测试替身的分类,现在就来认识一下它们,并了解相互的区别,以及运用它们的典型目的.我们先从最简单的开始. 3.2.1 测试桩通常是短小的 我这样来定义它:桩(名词),截断的或非常短的物体.这衍生出测试桩的精确定义.测试桩(简称桩或Stub)的目的是用最简单的可能实现来代替真实实现.最基本的实现例子就是一个对象的所有方法都只有一

交互设计师如何做交互?

交互设计师到底是需要做什么? 尽管很多谈及交互的书上都已经回答过了: 发现用户需要,建立明确需求 提出设计方案 制作设计原型 用户测试和评估 还是有很多对交互设计有兴趣的朋友会问我这个问题,并希望我能回答得详细,具体到我工作中的每个细节. 其实交互设计需要做什么,会随每个交互设计师的工作内容差异而不同,具体到每个项目也会有区别. 下面分享下我是怎样做交互,方式不一定是最合适,希望大家多指点,共同学习进步. 发现用户而要,建立明确需求 发现用户需要的方式有很多种,我们可以在用户反馈里收集到许多用户

我怎样做交互

交互设计师到底是需要做什么? 尽管很多谈及交互的书上都已经回答过了: 发现用户需要,建立明确需求提出设计方案制作设计原型用户测试和评估 还是有很多对交互设计有兴趣的朋友会问我这个问题,并希望我能回答得详细,具体到我工作中的每个细节. 其实交互设计需要做什么,会随每个交互设计师的工作内容差异而不同,具体到每个项目也会有区别. 下面分享下我是怎样做交互,方式不一定是最合适,希望大家多指点,共同学习进步. 发现用户需要的方式有很多种,我们可以在用户反馈里收集到许多用户提出的想法,他们希望我们能提供帮助

PowerPoint做交互课件 不用VBA照样搞定

要想用PowerPoint做交互课件,就必须会VBA编程,这是大家普遍的认识.其实,在用PowerPoint做教学课件时,即使不会VBA,也有许多方法可以做出动感十足的交互效果. 一.用"超链接"的方法 第一步:新建一文档,输入题目.选项.为设计方便,在这里选项设置为三个.设置文本内容的字体.字号.颜色.位置等属性. 第二步:连续复制当前页(根据选项个数,在这里复制三次),然后分别在每个复制页的一个选项的旁边加上评语,如"正确"或"错误".具体设

几个做交互设计的误区

  传统的设计,主要走的是视觉路子,这块儿东西挖得很深;讲究传达,把设计师想表达的东西.情感.境界通过设计的内容传达给用户;而现代设计,除了表达这些元素之外,更讲究"用户体验""沉浸式""用户行为和操作",这些元素都必须综合的加以考虑,才能得到用户的认可. 简单来说,主要就是加入了"交互"概念.现在各种概念有很多,简单来说,就是这个设计好的东西,对用户操作,"有反应",这种"反应"将赋予

如何用Jmeter做压力测试

Jmeter是一个性能测试工具,同loadrunner类似,他功能较多,我们常用的功能是用jmeter模拟多浏览器对网站做压力测试. 下载jmeter地址 :http://jakarta.apache.org/site/downloads/downloads_jmeter.cgi 我们一般的网站,在进入业务功能前先需登录,然后才能访问业务功能.下面介绍如何用jmeter登录系统再对主业务做压力测试. 1. 运行jmeter 2. 左边树将出现测试计划.工作台两根节点. 3. 选择测试计划,按右键

.net-大家做元测试的时候虚拟路径的问题如何处理的

问题描述 大家做元测试的时候虚拟路径的问题如何处理的 今天在做单元测试,程序是关于xml操作的,于是涉及一个路径问题. 我不得我在代码中将 //string path = System.Web.HttpContext.Current.Server.MapPath(xmlPath); string path = xmlPath; 然后传给xmlPath一个绝对路径,但如果要部署到网上,必然要使用虚拟路径. 虽然这样操作能够达到测试目的了,可否有不需要这么注释的方法呢?

Python中使用Boolean操作符做真值测试实例_python

在Python中,任何类型的对象都可以做真值测试,并且保证返回True或者False. 以下几种值(不论类型)在真值测试中返回False: 1.None 2.False 3.任何类型的数字0,包括0,0.0,0L,0j 4.空的序列(sequence)或者映射(mapping)类型对象 5.对于用户自定义类型的对象,如果其类定义了__nonzero__() 或者 __len__()特殊方法并且返回False或者0 对于最后一条规则,有几点需要说明: 1.如果类没有定义这两个方法中的任何一个,则这

谁说SKETCH不能做交互设计?

  今天抽空看了下Silver这款插件,这是首款内置于Sketch的交互插件,通过它,你可以不用再依赖其它软件,就可以在Sketch中完成交互方案的设计和展示工作,听起来还是很酷的.现在Silver还没有面世,先看看这篇介绍Silver特性的文章吧. 最近交互工具可真是风生水起不断涌现,从原生的Xcode,还有这几个号称不用写代码的的Hype3,Pixate,再到Principle,还有Flinto,还有这个正在开发过程中的Silver.不知道大家是不是已经挑花眼了呢? 不管你是哪个工具的粉,我