moq(发音"Mock-you" 或 "Mock")是.net的模拟框架,它从开始开发就充分利用.net3.5(如:linq表达式树)和C#3.0(如:lambda表达式)的特性,使它成为最富有创造力、类型安全、友好重构的模拟框架成为可能。它既支持模拟接口又支持模拟类。它的API简洁明了,使用模拟的概念预先不需要学习任何知识和经验。
上面一段话是英文的原话翻译,读完之后可以了解到moq是一个模拟框架,而且使用起来非常简单。但是,moq到底是什么,它适用于何种情况能够解决什么不得而知。下面就揭开moq小姐的面纱。
有位先生对moq小姐比较了解,他告诉我moq是用来伪装和隔离被依赖的对象,从而提高被测对象的测试效果。这位先生比较高深,而我只是个小小的程序猿,思考半天才明白了一些。在单元测试中,加桩(为了让一个模块执行起来,额外添加的一些支撑代码)是无法避免的,不使用moq(或其它模拟框架)就需要手动加桩。单元测试中另一个比较常见的问题就是数据的持久化,比如,专注于业务逻辑,数据持久化还没有实现,即使实现了,也不想单元测试影响到数据库的内容。下面我用代码来解释上面的话。
最近城管执法比较暴力,还打死了人,打死人当然要被警察叔叔刑拘的,下面的代码就是关于此的场景。
首先建立一个类库项目(WhatIsMoq.Model)和测试项目(WhatIsMoq.Tests),在WhatIsMoq.Model项目中新建一个IEnforceLaw接口以及PoliceEnforceLaw和ChenGuanEnforceLaw类分别实现IEnforceLaw接口。具体代码如下所示:
/// <summary>
/// 执法接口
/// </summary>
public interface IEnforceLaw
{
//杀人
bool KillPeople();
//抓人
bool GraspPeople();
}
//警察执法
public class PoliceEnforceLaw : IEnforceLaw
{
//警察执法依赖于城管执法,因为城管杀了人,警察才抓城管
IEnforceLaw _chengguanEnforceLaw;
public PoliceEnforceLaw(IEnforceLaw chengguanEnforceLaw)
{
_chengguanEnforceLaw = chengguanEnforceLaw;
}
public bool KillPeople()
{
return false;
}
//城管杀了人,警察抓城管
public bool GraspPeople()
{
return _chengguanEnforceLaw.KillPeople();
}
}
//城管执法(没有具体实现)
public class ChenGuanEnforceLaw : IEnforceLaw
{
public bool KillPeople()
{
throw new NotImplementedException();
}
public bool GraspPeople()
{
throw new NotImplementedException();
}
}
由于城管执法没有具体实现,在对警察执法单元测试时,由于它依赖于城管执法,因此单元测试无法进行,这个时候就需要添加额外的代码(加桩)来支撑单元测试。考虑到城管KillPeople有true和false两种情况,因此,要添加两个城管执法的加桩代码。如下代码是城管执法的加桩代码:
//城管执法返回KillPeople返回True的加桩代码
public class MockChenGuanEnforceLawKillPeopleReturnTrue : IEnforceLaw
{
public bool KillPeople()
{
return true;
}
public bool GraspPeople()
{
throw new NotImplementedException();
}
}
//城管执法返回KillPeople返回False的加桩代码
public class MockChenGuanEnforceLawKillPeopleReturnFalse : IEnforceLaw
{
public bool KillPeople()
{
return false;
}
public bool GraspPeople()
{
throw new NotImplementedException();
}
}
下面来写两个测试用例,如下所示:
[TestClass]
public class WhatIsMoqTest
{
//警察抓城管测试用例
[TestMethod]
public void Police_Grasp_ChengGuan()
{
PoliceEnforceLaw pel = new PoliceEnforceLaw(new MockChenGuanEnforceLawKillPeopleReturnTrue());
var grasp = pel.GraspPeople();
Assert.AreEqual(true, grasp);
}
//警察不抓城管测试用例
[TestMethod]
public void Police_Not_Grasp_ChengGuan()
{
PoliceEnforceLaw pel = new PoliceEnforceLaw(new MockChenGuanEnforceLawKillPeopleReturnFalse());
var grasp = pel.GraspPeople();
Assert.AreEqual(false, grasp);
}
}
通过上面的例子可以看到,如果没有模拟框架,就需要自己来写加桩代码,反之,如果利用moq模拟框架,则可以大大简化开发效率。下面来看一下使用moq的测试代码:
Mock<IEnforceLaw> chengguanEnforceLaw;
//创建城管执法的模拟对象
[TestInitialize]
public void Create_ChengGuan_EnforceLaw_Mock()
{
chengguanEnforceLaw = new Mock<IEnforceLaw>();
}
//使用Moq的警察抓城管测试用例
[TestMethod]
public void Police_Grasp_ChengGuan_Test_With_Moq()
{
//var chengguanEnforceLaw = new Mock<IEnforceLaw>();
chengguanEnforceLaw.Setup(t => t.KillPeople()).Returns(true);
PoliceEnforceLaw pel = new PoliceEnforceLaw(chengguanEnforceLaw.Object);
var grasp = pel.GraspPeople();
Assert.AreEqual(true, grasp);
}
//使用Moq的警察不抓城管测试用例
[TestMethod]
public void Police_Not_Grasp_ChengGuan_Test_With_Moq()
{
//var chengguanEnforceLaw = new Mock<IEnforceLaw>();
chengguanEnforceLaw.Setup(t => t.KillPeople()).Returns(false);
PoliceEnforceLaw pel = new PoliceEnforceLaw(chengguanEnforceLaw.Object);
var grasp = pel.GraspPeople();
Assert.AreEqual(false, grasp);
}
下面来看一下单元测试的结果:
本篇文章的前面部分解释了什么是moq,能干什么,后面部分给出了一个例子助于理解,现在终于可以看到moq小姐的真面纱了。
本文源代码下载地址:
链接:http://pan.baidu.com/share/link?shareid=3631839997&uk=2466437167 密码:c64f