[译] 什么是Mocking framework?它有什么用?

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

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

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

  1. public class Driver
  2. {
  3. private IVehicle vehicleToDrive;
  4. public Driver(IVehicle vehicleToDrive)
  5. {
  6. this.vehicleToDrive = vehicleToDrive;
  7. }
  8. public bool EvasiveManeuvers(bool alertOffendingDriver)
  9. {
  10. bool success = false;
  11. if (alertOffendingDriver)
  12. success = this.vehicleToDrive.ApplyBrakes() && this.vehicleToDrive.HonkHorn();
  13. else
  14. success = this.vehicleToDrive.ApplyBrakes();
  15. return success;
  16. }
  17. }

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

  1. public interface IVehicle
  2. {
  3. ///<summary>
  4. ///Honks the vehicle's horn.
  5. ///</summary>
  6. ///<returns>
  7. ///True if the action was successful.
  8. ///</returns>
  9. bool HonkHorn();
  10. ///<summary>
  11. ///Applies the vehicle's brakes.
  12. ///</summary>
  13. ///<returns>
  14. ///True if the action was successful.
  15. ///</returns>
  16. bool ApplyBrakes();
  17. }

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

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

  1. public class FakeVehicle : IVehicle
  2. {
  3. public int CalledHonkHorn = 0;
  4. public int CalledApplyBrakes = 0;
  5. public bool HonkHorn()
  6. {
  7. this.CalledHonkHorn++;
  8. return true;
  9. }
  10. public bool ApplyBrakes()
  11. {
  12. this.CalledApplyBrakes++;
  13. return true;
  14. }
  15. }

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

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

  1. [TestMethod]
  2. public void Can_Evade_Trouble()
  3. {
  4. // Arrange (set up a scenario)
  5. FakeVehicle fakeVehicle = new FakeVehicle();
  6. Driver target = new Driver(fakeVehicle);
  7. // Act (attempt the operation)
  8. bool success = target.EvasiveManeuvers(false);
  9. // Assert (verify the result)
  10. Assert.IsTrue(success);
  11. Assert.IsTrue(fakeVehicle.CalledHonkHorn == 0);
  12. Assert.IsTrue(fakeVehicle.CalledApplyBrakes == 1);
  13. }
  14. [TestMethod]
  15. public void Can_Evade_Trouble_And_Alert_Offending_Driver()
  16. {
  17. // Arrange (set up a scenario)
  18. FakeVehicle fakeVehicle = new FakeVehicle();
  19. Driver target = new Driver(fakeVehicle);
  20. // Act (attempt the operation)
  21. bool success = target.EvasiveManeuvers(true);
  22. // Assert (verify the result)
  23. Assert.IsTrue(success);
  24. Assert.IsTrue(fakeVehicle.CalledHonkHorn == 1);
  25. Assert.IsTrue(fakeVehicle.CalledApplyBrakes == 1);
  26. }

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就可以了。

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

  1. [TestMethod]
  2. public void Can_Evade_Trouble()
  3. {
  4. // Arrange (set up a scenario)
  5. Mock<IVehicle> mock = new Mock<IVehicle>();
  6. mock.Setup(x => x.ApplyBrakes()).Returns(true);
  7. Driver target = new Driver(mock.Object);
  8. // Act (attempt the operation)
  9. bool success = target.EvasiveManeuvers(false);
  10. // Assert (verify the result)
  11. Assert.IsTrue(success);
  12. mock.Verify(x => x.HonkHorn(), Times.Never());
  13. mock.Verify(x => x.ApplyBrakes(), Times.Once());
  14. }
  15. [TestMethod]
  16. public void Can_Evade_Trouble_And_Alert_Offending_Driver()
  17. {
  18. // Arrange (set up a scenario)
  19. Mock<IVehicle> mock = new Mock<IVehicle>();
  20. mock.Setup(x => x.HonkHorn()).Returns(true);
  21. mock.Setup(x => x.ApplyBrakes()).Returns(true);
  22. Driver target = new Driver(mock.Object);
  23. // Act (attempt the operation)
  24. bool success = target.EvasiveManeuvers(true);
  25. // Assert (verify the result)
  26. Assert.IsTrue(success);
  27. mock.Verify(x => x.HonkHorn(), Times.Once());
  28. mock.Verify(x => x.ApplyBrakes(), Times.Once());
  29. }

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

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

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

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

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

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

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

  1. 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。

  1. //Do this
  2. Mock<IVehicle> mock = new Mock<IVehicle>();
  3. Driver driver = new Driver(mock.Object);
  4. //Not this
  5. Mock<IVehicle> mock = new Mock<IVehicle>();
  6. Driver driver = new Driver(mock);

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

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

【转载请注明出处】
 
分类: C#
标签: moqmockingunit test

Mocking framework的更多相关文章

  1. Testing with a mocking framework (EF6 onwards)

    When writing tests for your application it is often desirable to avoid hitting the database.  Entity ...

  2. 什么是Mocking framework?它有什么用?

    原位地址:http://codetunnel.com/blog/post/what-is-a-mocking-framework-why-is-it-useful 今天我想讲下关于mocking fr ...

  3. What is a mocking framework? Why is it useful?

    Today I want to talk about mocking frameworks and why they are useful. In order to do that I first n ...

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

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

  5. Googletest - Google Testing and Mocking Framework

    Googletest - Google Testing and Mocking Framework https://github.com/google/googletest

  6. 利用Mocking Framework 单元测试Entity Framework

    一.前言 在实际编写程序时,往往需要与数据库打交道,在单元测试中直接使用数据库又显得太重,如果可以方便的编写一些测试数据,这样更易于检测功能.如何模拟数据库行为便是本篇的主题.微软有教程说明Moq E ...

  7. JustMock Lite (Free Mocking Framework For .net)

    通过 Nuget 安装 2.   官网下载(官网不行点这里) 3.   帮助文档 商业版和免费版区别概览 MockingContainer 测试类准备:一般来说也是业务类 public class C ...

  8. 第一篇:Entity Framework 简介

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

  9. Entity Framework版本历史概览

    转自:http://www.cnblogs.com/fecktty2013/archive/2014/09/26/entityframework-overview.html EF版本 .net fra ...

随机推荐

  1. windows phone8.1:Xml,Json序列化和反序列化

    原文:windows phone8.1:Xml,Json序列化和反序列化 小梦本例主要实现以下四点内容: 将Car对象序列化为xml 将Car对象序列化为Json 将xml反序列化为Car对象 将js ...

  2. 菜鸟学Java(二十一)——怎样更好的进行单元測试——JUnit

    測试在软件生命周期中的重要性,不用我多说想必大家也都很清楚.软件測试有许多分类,从測试的方法上可分为:黑盒測试.白盒測试.静态測试.动态測试等:从软件开发的过程分为:单元測试.集成測试.确认測试.验收 ...

  3. VS2012编写C语言项目

    原文:VS2012编写C语言项目 这两天看了一下C语言方面的知识,大学的时候使用的Turbo C对于我来说已经是很久之前的事情了,编写C语言的还有VC++,不过这货在64的表现实现是很让人失望,还是用 ...

  4. windows下exfat无法写入修复

    为了可以实现mac与windows文件共享,把移动硬盘格式化为exfat了,但是在osx中放入文件后,在windows上紧进行读取写入时出现错误,提示使用chkdsk进行修正,以下是修正步骤. ①wi ...

  5. 在打包程序中自动安装SQL Server数据库 .

    原文:在打包程序中自动安装SQL Server数据库 . 1.创建安装项目“Setup1”安装项目 在“文件”菜单上指向“添加项目”,然后选择“新建项目”. 在“添加新项目”对话框中,选择“项目类型” ...

  6. jQuery.extend()源码解读

    // extend方法为jQuery对象和init对象的prototype扩展方法// 同时具有独立的扩展普通对象的功能jQuery.extend = jQuery.fn.extend = funct ...

  7. javascript6

    eval("3+2")//5 eval():全局eval():严格eval() 函数和可执行的对象(callable object) delete一元操作符,善处对象属性或者数组元 ...

  8. Ninject.Extensions.

    最近在使用IoC进行一个较复杂的项目进行架构,在IoC的选择上让我很是纠结.首先我不喜欢大量的配置文件进行配置,那简直是噩梦,比学习一门编程语言还痛苦.我喜欢前一段时间看EF的CodeFirst的那种 ...

  9. OpenSUSE13.2安装MongoDB

    真是一个悲伤的故事,就是你解决过得问题没有记住,却需要再通过搜索引擎来找一遍,幸运的是曾经你做过记录,搜索帮你找到了. 这是我一个Wordpress博客整理记录的,好久没在那里更新了,两个月的时间,我 ...

  10. shell awk统计重复个数

    awk是一个很强大的工具,一个常见的用法就是统计一个文件中重复的列值的个数,这也是面试时面试官经常问的一个问题. 举个例子: 有个文件file.log的内容如下: http://www.sohu.co ...