Moq & RhinoMocks

使用Mock对象进行测试一般都会有以下三个关键步骤:

  1. 使用接口来描述需要测试的对象
  2. 为实际的产品代码实现这个接口
  3. 以测试为目的,在Mock对象中实现这个接口

在使用Mock对象的过程中,充分体现出了“面向接口编程”的设计原则,同时也促成类的良好设计。

自行实现Mock对象是相当繁琐的工作,让人幸运的是,在.NET世界中有多个优秀的Mock框架可以供大家选择,目前最常使用的无非Moq与Rhino Mocks这两个框架。两者的最新版本在Mocking API方面的用法已日趋一致,都依托Lambda表达式、泛型和扩展方法做了很大改进,目标都是让Mock对象以一种更自然的方式与多个单元测试框架进行集成,以一种清晰的语法来描述期望值、参数约束、返回值等,极大的方便开发者的使用。

由于Moq和Rhino Mocks都使用了Castle DynamicProxy这个类库动态生成代理类,因此对需要Mock的对象有一定的限制:所测试的方法必须是virtual类型。

下面就用一个例子来看看两者的不同实现(这个例子摘自Moq源代码包中的Samples,只是略做了些修改以便于展现两者的特点):

需要进行测试的对象如下示之:

展开

下面是用这两个Mock框架分别实现的单元测试代码:

Moq 4.0 Rhino Mocks 3.6
[Test]
public void TestPresenterSelection() {
// arrange
var mView = new Mock<IOrdersView>();
var mRepository = new Mock<IRepository<Order>>();
var presenter = new OrdersPresenter(mView.Object, mRepository.Object);
// check that the presenter has no selection by default
Assert.Null(presenter.SelectedOrder); // raise event
mView.Raise(io => io.OrderSelected += null,
new OrderEventArgs { Order = new Order("moq", 50) }); // assert
Assert.NotNull(presenter.SelectedOrder);
Assert.AreEqual("moq", presenter.SelectedOrder.ProductName);
}
[Test]
public void TestPresenterSelection() {
// arrange
var mView = MockRepository.GenerateMock<IOrdersView>();
var mRepository = MockRepository.GenerateMock<IRepository<Order>>();
var presenter = new OrdersPresenter(mView, mRepository);
// check that the presenter has no selection by default
Assert.Null(presenter.SelectedOrder); // raise event
mView.Raise(io => io.OrderSelected += null, null,
new OrderEventArgs { Order = new Order("moq", 50) }); // assert
Assert.NotNull(presenter.SelectedOrder);
Assert.AreEqual("moq", presenter.SelectedOrder.ProductName);
}
[Test]
public void TestRetrieveOrders() {
// arrange
var mView = new Mock<IOrdersView>();
var mRepository = new Mock<IRepository<Order>>();
var presenter = new OrdersPresenter(mView.Object, mRepository.Object); List<Order> defaultOrders = new List<Order>
{ new Order("moq"), new Order("RhinoMock") }; mRepository.Setup(r => r.FindAll()).Returns(defaultOrders); // exercise mocks
presenter.OnInit();
// assert
mView.VerifySet(v => v.Orders = defaultOrders);
}
[Test]
public void TestRetrieveOrders() {
// arrange
var mView = MockRepository.GenerateMock<IOrdersView>();
var mRepository = MockRepository.GenerateStub<IRepository<Order>>();
var presenter = new OrdersPresenter(mView, mRepository); List<Order> defaultOrders = new List<Order>
{ new Order("moq"), new Order("RhinoMock") }; mRepository.Stub(ir => ir.FindAll()).Return(defaultOrders); // exercise mocks
presenter.OnInit();
// assert
mView.AssertWasCalled(v => v.Orders = defaultOrders);
}

Conclusion

通过上面的实例我们可以很容易看出两者的Syntax与API都非常接近,使用两者任何一个都能方便实现你的测试目的。

References

  1. QuickStart - Moq
  2. Ayende@Wiki - Rhino Mocks 3.5
  3. Daniel Cazzulino's Blog - Why do we need yet another NET mocking framework
 
分类: C#
标签: Moq, Rhino Mocks

Moq 和RhinoMocks的更多相关文章

  1. Moq 和 RhinoMocks

    我们在做单元测试的时候,利用mock可轻松构建出测试需要的类或接口,而不需要编写繁琐的测试代码. .net 下我知道Moq与Rhino Mocks这两个框架. Moq 网上介绍的比较多. Rhino ...

  2. Moq & RhinoMocks

    Moq & RhinoMocks 使用Mock对象进行测试一般都会有以下三个关键步骤: 使用接口来描述需要测试的对象 为实际的产品代码实现这个接口 以测试为目的,在Mock对象中实现这个接口 ...

  3. Moq 测试 属性,常用方法

    RhinoMock入门(7)——Do,With和Record-playback 摘要: (一)Do(delegate)有时候在测试过程中只返回一个静态的值是不够的,在这种情况下,Do()方法可以用来在 ...

  4. Moq基础

    一.概念 Moq是利用诸如Linq表达式树和Lambda表达式等·NET 3.5的特性,为·NET设计和开发的Mocking库.Mock字面意思即模拟,模拟对象的行为已达到欺骗目标(待测试对象)的效果 ...

  5. 单元测试与Moq

    这个篇幅里面,记录单元测试与Moq模拟包的知识点. 单元测试 每一个模块,都应该有对应的单元测试.单元测试可以保证你的代码准确性,大大减少出现BUG的几率.一个好的单元测试,也是重构代码必不可少的部分 ...

  6. moq 的常用使用方法

    测试方法                             Console.WriteLine(mock.Object.GetCountThing()); 匹配参数   mock.Setup(x ...

  7. 单元测试中使用Moq对EF的DbSet进行mock

    刚用上Moq,就用它解决了一个IUnitOfWork的mock问题,在这篇博文中记录一下. 开发场景 Application服务层BlogCategoryService的实现代码如下: public ...

  8. 【MVC 4】4.MVC 基本工具(Visual Studio 的单元测试、使用Moq)

     作者:[美]Adam Freeman      来源:<精通ASP.NET MVC 4> 3.Visual Studio 的单元测试 有很多.NET单元测试包,其中很多是开源和免费的.本 ...

  9. 【Pro ASP.NET MVC 3 Framework】.学习笔记.4.MVC的主要工具-使用Moq

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

随机推荐

  1. Linux 编程学习笔记----过程管理和项目发展(在)

    转载请注明出处,http://blog.csdn.net/suool/article/details/38406211,谢谢. Linux进程存储结构和进程结构 可运行文件结构 例如以下图: 能够看出 ...

  2. 每位iOS开发人员不容错过的10大实用工具

    内容简介 1.iOS简介 2.iOS开发十大实用工具之开发环境 3.iOS开发十大实用工具之图标设计 4.iOS开发十大实用工具之原型设计 5.iOS开发十大实用工具之演示工具 6.iOS开发十大实用 ...

  3. 构造函数为什么不能为虚函数 &amp; 基类的析构函数为什么要为虚函数

    一.构造函数为什么不能为虚函数 1. 从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,这大家都知道,但是这个指向vtable的指针事实上是存储在对象的内存空间的.问题出来了,假设构造函数 ...

  4. (hdu step 6.3.5)Card Game Cheater(匹配的最大数:a与b打牌,问b赢a多少次)

    称号: Card Game Cheater Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...

  5. 苹果WatchKit轻松入门

    背景 前段时间苹果Apple推出 WatchKit,用于开发Apple Watch应用,同时也推出了 Xcode6.2 Beta(非稳定版,好期待稳定版)版本用于开发 Watch App.Apple ...

  6. [leetcode] Combination Sum and Combination SumII

    Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C wher ...

  7. Android Tween Animation

    View Animation, 它显示在view向上Tween Animation Tween动画.本质上没有变化View对象本身.只要改变它绘制 实施方式有两种.一个xml定义,直接在代码中的定义 ...

  8. Mac OS温馨提示17:七彩花哨的输入

    OSX Mavericks中国的文字输入功能,色于windows,甚至提供了强大的手写输入功能和语音输入功能,而且发展到如今,已经有非常多种第三方输入法支持Mac了. 一.主要的输入法        ...

  9. MEF初体验之十二:Composition Batch

    一个MEF容器实例是不可变的.如果catalog支持改变(像观察一个目录的改变)或是如果你的代码在运行时添加或移除部件,改变都可能发生.以前,你不得不作出改变并在组合容器上调用它的组合方法.在Prev ...

  10. C#+Mapxtreme 实现一些GIS系统基本的功能

    此程序包括了mapxtreme地图相关基本功能的演示其中包括 鹰眼地图,图层控制,发达,缩小,平移地图,地图模糊查询,中点工具,距离测量工具,面积测量工具,图元信息查看工具.适合于企业级开发,可以为您 ...