在之前的例子中,我们创建了FakeRepository类来支持我们的测试。但是我们还没有解释如何穿件一个真实的repository实现,我们需要一个替代品。一旦我们有一个真的实现,我们可能不会再用它,因为它把我们的测试环境变得复杂。

FakeRepository类,是IProductRepository接口的伪实现。我们创建伪实现,并手动添加特别的参数,使得FakeRepository类手动的仿制品。Moq是一个框架,让我们仿制变得快速,简单,容易。

1 将Moq添加到测试项目,而不是应用程序项目

2 使用Moq创建一个Mock

使用mocking工具的好处是,我们能创建一个为满足测试中的功能定制的Mocks。这意味着我们最终不会得到太复杂的mock实现。在一个真实的项目中,不像这些简单的例子。我们能容易地抵达舞台,mock实例需要它自己的测试,因为它包含足够的代码。我们能手工创建一些mock,为了使它们生效,我们需要移动循环代码到基类,我们正确的返回会变得更复杂。有两个舞台需要使用Moq创建mock,第一个创建一个新的Mock<T>,这个T是我们想要mock的。

第二个舞台是配置实现要展示的行为。Moq会自动实现我们在类型中给它的所有的方法和属性,它会使用类型的默认值。例如,IProductRepository.GetProducts方法会返回一个空的IEnumerable<Product>。要改变Moq实现一个类型成员的方法,我们需要使用Setup方法。

3 使用Moq方法选择器

第一个参数是被选择的方法。Moq使用Linq和Lambda表达式。当我们调用Setup方法,Moq传递接口。当我们想要为GetProducts方法定义一个行为,我们可以这样做

mock.Setup(m => m.GetProducts()).(<...other methods...>);

我们不需要知道它内部是怎样工作的,只需要照着做就行了。GetProduct方法容易处理,是因为它没有参数。如果我们想要处理携带参数的方法,我们需要考虑第二个元素:参数过滤。

4 使用Moq的参数渗透

mock.Setup(m => m.ProcessMessage("bye")).Returns("See you soon");

要为所有可能的参数设置相应,可以使用Moq提供的It类。

mock.Setup(m => m.ProcessMessage(It.IsAny<string>())).Returns("Message received");

It类定义一些方法,配合一般型参数使用。我们调用IsAny方法,使用string作为一般类型。这告诉Moq,当ProcessMessage方法伴着任何string值被调用,它会返回相应Message Recived。

Method Description
Is<T>() 匹配基于指定的条件
IsAny<T>() 当参数是任何T类型的实例时匹配
IsInRange<T> 当参数在指定值之间时匹配
IsRegex 当匹配指定的正则表达式时匹配

Is<T>方法时最灵活的,因为它让我们提供一个条件。

.Returns("Message received");

当string参数是hello或bye时,返回Message Recived。

5 返回一个结果

当我们配置行为时,我们也定义它被触发时的返回方法。上个例子中,Returns方法链式地Setup方法。我们也可以使用传递给mocked方法的参数,给Return方法,让output基于input。

.Returns<string>(s =>string.Format("Message received: {0}", s));

6 使用Moq的单元测试

一旦配置好必须的行为,你可以通过Mock.Object属性得到mocked的实现。

}

为所有测试准备公共数据。单元测试的属性:

Attribute Description
ClassInitialize 在类中的单元测试被执行之前调用。必须应用给静态方法
ClassCleanup 在类中的所有方法执行完成后调用。必须应用给静态方法
TestInitialize 在每个测试执行前调用
TestCleanup 在每个测试执行后调用

VS只看这些属性,方法的名字不重要。

7 使用Moq验证

当每个Product对象被处理时,UpdateProduct方法会被调用。在FakeRepository类中,我们我们定义了一个自增的属性。我们能用Moq以更优美的方式实现相同的效果。

}

使用参数渗透,我们能验证UpdateProduct方法,恰好被每个Product对象调用一次。

最新文章

  1. Common.Logging log4net Common.Logging.Log4Net 配置
  2. 第一个jemter测试脚本
  3. MemSQL分布式架构介绍(一)
  4. C#中使用DateTimePicker控件显示修改日期时间
  5. Ranorex入门指南
  6. FLASH CC 2015 CANVAS (二)html中写JS调用flash中的元件、函数、变量
  7. C#inSSIDer强大的wifi无线热点信号扫描器源码
  8. C#5.0之后推荐使用TPL(Task Parallel Libray 任务并行库) 和PLINQ(Parallel LINQ, 并行Linq). 其次是TAP(Task-based Asynchronous Pattern, 基于任务的异步模式)
  9. Unity3D 之武器系统冷却功能的实现方式
  10. VS2013单元测试
  11. VC 串口通信类
  12. 理解Java多态
  13. NGUI判断是否点击到UI控件
  14. 两句话帮你彻底记住gdb之eXamining memory
  15. Request.getparameternames 获取form表单里面所有的请求参数 。 返回一个Enumeration类型的枚举.
  16. 笔记︱集成学习Ensemble Learning与树模型、Bagging 和 Boosting
  17. HTTP协议中PUT和POST使用区别
  18. 20.react库 入门
  19. Linux中 Lua 访问Sql Server的配置方法
  20. linux之master和minion

热门文章

  1. [BS-07] 创建和使用PCH File
  2. iOS UILabel根据文字获取高度及UITableCell动态获取高度(以截取快递信息为例)
  3. cocos2dx 3.x(精灵的碰撞检测,点击移动与拖动精灵)
  4. C# 匿名方法
  5. docker note
  6. 在xocde运行profile 遇到&quot;Existing default base temp directory &#39;/Library/Caches/com.apple.dt.instruments&#39; has insufficient privileges for user id 505. Please have the owner delete this directory&quot;
  7. JavaScript内的类型转换
  8. hduoj 4712 Hamming Distance 2013 ACM/ICPC Asia Regional Online —— Warmup
  9. ACM-ICPC竞赛模板
  10. 为什么接口要规定成员变量必须是public static final的呢?(转)