原位地址:http://codetunnel.com/blog/post/what-is-a-mocking-framework-why-is-it-useful

今天我想讲下关于mocking frameworks,并且解释下他为什么有用处。我将给你们展示用和不用mocking framework两种测试方法。

假设我们已经有了一个Driver类:

public class Driver
{private IVehicle vehicleToDrive;public Driver(IVehicle vehicleToDrive){this.vehicleToDrive = vehicleToDrive;}public bool EvasiveManeuvers(bool alertOffendingDriver){bool success = false;if (alertOffendingDriver)success = this.vehicleToDrive.ApplyBrakes() && this.vehicleToDrive.HonkHorn();elsesuccess = this.vehicleToDrive.ApplyBrakes();return success;}
}

【注意】Driver类的构造函数依赖IVehicle接口!定义如下:

public interface IVehicle
{///<summary>///Honks the vehicle's horn.///</summary>///<returns>///True if the action was successful.///</returns>bool HonkHorn();///<summary>///Applies the vehicle's brakes.///</summary>///<returns>///True if the action was successful.///</returns>bool ApplyBrakes();
}

  现在我们需要写2个单元测试来测试Driver。然而在我们写之前,必须能够通过Driver的构造函数才行,他依赖IVehicle接口。
很多人认为只要随便实现IVehicle就可以了,这当然没问题。事实上,如果你完成接口IVechicle,你也不用写单元测试了。
单元测试是孤立性的,测试Driver类并且还要实现一个完整IVehicle实现不是单元测试,那是整体封闭测试。如果你在测试时出错了,你不能确认是Driver出错了还是其他的类。

我们现在搞一个假的IVehicle的实现来解决这个依赖问题。

public class FakeVehicle : IVehicle
{public int CalledHonkHorn = 0;public int CalledApplyBrakes = 0;public bool HonkHorn(){this.CalledHonkHorn++;return true;}public bool ApplyBrakes(){this.CalledApplyBrakes++;return true;}
}

注意我们定义的两个int成员,在我们的单元测试中我们将用他们判断HonkHorn()和ApplyBrakes()的调用情况。

现在我们可以写单元测试了,我们将测试两个行为:
1、Can_Evade_Trouble
2、Can_Evade_Trouble_And_Alert_Offending_Driver

[TestMethod]
public void Can_Evade_Trouble()
{// Arrange (set up a scenario)FakeVehicle fakeVehicle = new FakeVehicle();Driver target = new Driver(fakeVehicle);// Act (attempt the operation)bool success = target.EvasiveManeuvers(false);// Assert (verify the result)Assert.IsTrue(success);Assert.IsTrue(fakeVehicle.CalledHonkHorn == 0);Assert.IsTrue(fakeVehicle.CalledApplyBrakes == 1);
}[TestMethod]
public void Can_Evade_Trouble_And_Alert_Offending_Driver()
{// Arrange (set up a scenario)FakeVehicle fakeVehicle = new FakeVehicle();Driver target = new Driver(fakeVehicle);// Act (attempt the operation)bool success = target.EvasiveManeuvers(true);// Assert (verify the result)Assert.IsTrue(success);Assert.IsTrue(fakeVehicle.CalledHonkHorn == 1);Assert.IsTrue(fakeVehicle.CalledApplyBrakes == 1);
}

OK,现在我们成功的通过单元测试。他们的EvasiveManeuvers()方法都返回true,并且IVechicle.ApplyBrakes()方法每次都被调用了,HonkHorn()方法第一个测试没有被调用,第二次调用了。
注意,在真正的测试驱动开发 TDD(Test Driven Development)我们首先要写测试,然后才是写代码再测试,但我们没这么做。

这是一个比较不太讨人喜欢的写测试的风格,为了通过Driver我们写了一个FakeVehicle,假如需要写很多这种类那就麻烦了。

为了解决这种问题,Mocking Framework诞生了。

我们现在用一个叫Moq的框架(https://code.google.com/p/moq/),他的语法独特,但用过之后你会感到写起来很流畅。只要把moq.dll添加到引用,然后using Moq就可以了。

现在我们重写上面的测试代码,回头再解释它的牛逼的地方。

[TestMethod]
public void Can_Evade_Trouble()
{// Arrange (set up a scenario)Mock<IVehicle> mock = new Mock<IVehicle>();mock.Setup(x => x.ApplyBrakes()).Returns(true);Driver target = new Driver(mock.Object);// Act (attempt the operation)bool success = target.EvasiveManeuvers(false);// Assert (verify the result)Assert.IsTrue(success);mock.Verify(x => x.HonkHorn(), Times.Never());mock.Verify(x => x.ApplyBrakes(), Times.Once());
}[TestMethod]
public void Can_Evade_Trouble_And_Alert_Offending_Driver()
{// Arrange (set up a scenario)Mock<IVehicle> mock = new Mock<IVehicle>();mock.Setup(x => x.HonkHorn()).Returns(true);mock.Setup(x => x.ApplyBrakes()).Returns(true);Driver target = new Driver(mock.Object);// Act (attempt the operation)bool success = target.EvasiveManeuvers(true);// Assert (verify the result)Assert.IsTrue(success);mock.Verify(x => x.HonkHorn(), Times.Once());mock.Verify(x => x.ApplyBrakes(), Times.Once());
}

不管你信不信,反正我们可以丢掉FakeVehicle类了。
Moq动态的构造了接口的实现类,所有的成员默认的值都是其默认值。
由于bool类型的默认值是false,所以HonkHorn()ApplyBrakes()在mock.Object实例中都将返回false,显然我希望返回true的,所以用Moq的Setup()方法来解决。

Setup参数是一个lambda表达式,可以强类型的方式直接访问到其成员。例如

mock.Setup(x=>x.HonkHorn().Returns(true));

如果不用lambda用字符串,类似mock.Setup("HonkHorn").Returns(true),这种方式比较丑,如果接口变化了这边就该报错了。
moq用lambda就是保证所有的访问都是强类型的。

另外如果你的方法接受一些参数比如string例如

mock.Setup(x => x.HonkHorn("loudly");

如果这个值不是必须的(不是这个值就不能通过),那就可以用It类代替,他包含很多有用的方法。下面的例子就是接受任意字符串

mock.Setup(x => x.HonkHorn(It.IsAny<string>())).Returns(true);

Moq可以让你创建任意类型T的Mock<T>实例,然后调用Setup()去设置属性或方法的返回值,随便什么值只要是为你达到测试的目的。加入你需要一个属性返回一个集合,你只需要定义好集合类,并且通过Setup()的Returns方法返回集合就行了。当这个mock.Object的集合属性被访问时就会返回你定义好的集合。
记住:1、mock的对象不是你的测试,你mock的对象是让你能够通过他们进入你要测试的类/组件。
另外注意 var mock = new Mock<T>。mock可不是T的实例,mock是Mock<T>的对象实例,T的实例是mock.Object。所以不要搞混了;实例化Driver时要用mock.Object。

//Do this
Mock<IVehicle> mock = new Mock<IVehicle>();
Driver driver = new Driver(mock.Object);//Not this
Mock<IVehicle> mock = new Mock<IVehicle>();
Driver driver = new Driver(mock);

现在回过头看看我们的moq的单元测试,所有的结果都是对的。调用次数也是对的,moq能自动记录方法的调用次数,我们只需要调用mock.Verify()然后通过lambda表达式就能验证我们想要的次数是否正确。

这里是最基础的moq用法,希望你现在能够明白mockingframework的用处并明白moq怎么完成工作的。

  

  

  

 

什么是Mocking framework?它有什么用?相关推荐

  1. Google Mock启蒙篇 [1] (Google C++ Mocking Framework for Dummies 翻译)

    Google C++ Mocking Framework for Dummies Google Mock启蒙篇 Version: 0.07< xmlnamespace prefix =" ...

  2. Google Mock启蒙篇 [2] (Google C++ Mocking Framework for Dummies 翻译)

    Setting Expectations 成功地使用Mock对象的关键是在它上面设置合适的期望.如果你设置的期望太过严格,你的测试可能会因为无关的改变而失败.如果你把期望设置的太过松驰,bugs可能会 ...

  3. 什么是Mocking framework?它有什么用?(转)

    今天我想讲下关于mocking frameworks,并且解释下他为什么有用处.我将给你们展示用和不用mocking framework两种测试方法. 假设我们已经有了一个Driver类: [csha ...

  4. What Is Google C++ Mocking Framework?

    (Note: If you get compiler errors that you don't understand, be sure to consult Google Mock Doctor.) ...

  5. 第一篇:Entity Framework 简介

    先从ORM说起吧,很多年前,由于.NET的开源组件不像现在这样发达,更别说一个开源的ORM框架,出于项目需要,以及当时OOP兴起(总不至于,在项目里面全是SQL语句),就自己开始写ORM框架.要开发O ...

  6. Entity Framework 简介

    转贴:链接https://www.cnblogs.com/davidzhou/p/5348637.html 侵删,谢谢 第一篇:Entity Framework 简介 先从ORM说起吧,很多年前,由于 ...

  7. C++开源代码项目汇总

    Google的C++开源代码项目 v8  -  V8 JavaScript Engine V8 是 Google 的开源 JavaScript 引擎. V8 采用 C++ 编写,可在谷歌浏览器(来自 ...

  8. 一些C++的开源项目和C++库以及修炼C++的方法

     Google的C++开源代码项目 v8  -  V8 JavaScript Engine V8 是 Google 的开源 JavaScript 引擎. V8 采用 C++ 编写,可在谷歌浏览器( ...

  9. A Complete List of .NET Open Source Developer Projects

    http://scottge.net/2015/07/08/a-complete-list-of-net-open-source-developer-projects/?utm_source=tuic ...

最新文章

  1. 技术工坊|解密区块链DApp的代码逻辑,从请求到数据存储都要经历什么?(上海)...
  2. 强化深度学习把医疗AI推向新的高潮
  3. xxx must either be declared abstract or implement abstract method ‘call(T1, T2)‘ in ‘Function2
  4. echart中拆线点的偏移_Real BIM | Rhino+Grasshopper在双曲异形玻璃幕墙中的应用
  5. 算法与数据结构题目汇总
  6. 四面快手归来,分享Java真题及面经:策略模式+红黑树+Java锁+Redis+Kafka等分布式
  7. python 逻辑回归_不会Python没问题!用Excel实现简单的逻辑回归!
  8. 第7期 DApp 榜单:长夜将至,我们将至死守望
  9. 高中数学复习知识清单
  10. 3dmax制作光束效果教程!
  11. matlab课表编排程序实例,编排课程表的一点心得
  12. Spring Boot配置Tomcat容器、Jetty容器、Undertow容器
  13. property of non-object,yii错误
  14. WIN11win10 使用Anaconda下载Pytorch详细教程(包括换源)
  15. 2023兰州理工大学计算机考研信息汇总
  16. 【VFI系列2】视频内插帧中基于optical flow的 backward/forward warping
  17. 节省你学习时间的百余个谷歌小技巧
  18. hadoop -appendToFlie unknown command
  19. 何晓理(风过无痕)-从85年开始的学习经历
  20. php 获取服务器进程数,PHP 获取linux服务器性能CPU、内存、硬盘、进程等使用率...

热门文章

  1. 哈希(Hash)算法,用哈希表进行查找
  2. arcgis上下标问题
  3. react.js app_在React.JS中创建一个Weather App
  4. ifind设置自选股票池
  5. 实时推荐系统的3种方式
  6. spring boot文件下载加水印(pdf,word,pdf,照片,excel)
  7. Invalid use of argument matchers
  8. 51Testing独家连载:(七)精通QTP——自动化测试技术领航
  9. 微服务架构带来的分布式单体,更好还是更坏,一念之间
  10. Dreamweaver教程从入门到精通 html篮球网站制作 学生静态网页作业源码模板