【ASP.Net MVC3 】使用Moq让单元测试变得更简单

前几天调查完了unity。现在给我的任务是让我调查Moq。

以下是自己找了资料,总结并实践的内容。如果有表述和理解错误的地方。恳请指正。

什么是Moq?

Moq(英语发音是Mock-you 或者只是mock)是一个针对.Net开发的模拟库,它从开始就完全充分利用了.NET3.5(LINQ表达式树)和C#3.0的新特性(lambda表达式)。它的目标是让模拟以一种自然的方式与现有单元测试进行集成,使它更加简单、直观,以避免开发人员被迫重写测试或高成本的学习测试框架。这使它成为了一个高生产力、类型安全、重构友好的模拟库。

从哪得到Moq?

如果你看过我的其他文章,我们可以直接使用 VS中的插件Nuget来获取Moq并且引用到指定的项目。

否则,我们可以从http://code.google.com/p/moq/这里得到Moq的最新版本。

可以模拟什么?局限性

首先,模拟的类不能是密封的。

其次,你不能直接模拟静态方法。因为Moq只能创建模拟对象实例。在这种情况下,间接的解决方案是我们可以在要模拟对象外包装一层,并且去模拟这个新对象。这种模式被称为适配器模式。

通常我们测试一个方法,它有可能调用好几个service。但是每次都去访问这些service的代价是很高的。我们可以通过模拟的方法让它模拟访问service,并且根据不同请求模拟返回响应的结果。

Moq原理

Moq是如何办到的?它只需要一个接口类型就可以生产一个对象?没错,就是这样。Moq使用 Castle DynamicProxy 完成这个任务。基本原理就是它利用反射机制的 Emit 功能动态生成一个空类型(也就是所有接口的方法都实例化,但是没有任何功能,只是一个程序骨架)。所以Mock的能力就在于可以利用DynamicProxy的机制快速生产出一个假对象来,用于模仿真对象的行为。

Moq中的重要成员

Mock

通过这个类,我们可以得到一个Mock<T>对象。T可以是接口,也可以是类。它有一个public 和virtual属性。让我们看看下边的例子:

        //define interface to be mocked

public interface IFake        {

bool DoSomething(string actionname);

        }

//define the test method

        [TestMethod]

public void Test_Interface_IFake()        {

//make a mock Object by Moq

var mo = new Mock<IFake>();

//Setup our mock object

            mo.Setup(foo => foo.DoSomething("Ping"))

            .Returns(true);

//Assert it!

            Assert.AreEqual(true, mo.Object.DoSomething("Ping"));        }
复制代码

在上边的代码,我们通过传递泛型参数IFake去创建Mock<IFake>的实例 模拟接口IFake。

接下来我们要调用Setup()方法去创建我们的模拟对象。注意,Setup方法的参数是一个lambda表达式。我们可以这样理解:当被模拟的对象foo调用它自己的方法DoSomething(),并且参数是Ping。添加后缀 Return (true)我们可以理解为:前边的请求返回结果为真。这是我们指定的返回值。当一个请求调用DoSomething()方法时。如果传入的参数是Ping,那么我们会返回true。接下来,我们添加一个断言,去判断是否能得到预期结果。

注:Foo仅仅是一个词用作通用替代真实的东西,特别是在讨论技术想法和问题.

It

这是一个静态类,定义了静态的泛型方法:Is<TValue>, IsAny<TValue>, IsInRange<TValue>, 和IsRegex。去过滤参数。看看下边例子:

public interface IEmailSender        {

bool Send(string subject, string body, string email);

        }  [TestMethod]

public void User_Can_Send_Password()        {

var emailMock = new Mock<IEmailSender>();

            emailMock

            .Setup(sender => sender.Send(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))

            .Returns(true);

        }
复制代码

任何时候调用Send()方法,只要传入的参数是任何的string,我们定义他会返回true。

我们也可以根据lambda的优势订制一个规则:

  var productRepository = new Mock<IProductRepository>();

            productRepository

            .Expect(p => p.Get(It.Is<int>(id => id > 0 && id < 6)))

            .Returns(newProduct.Object);
复制代码

这样我们可以设置这个id在0和6之间的时候才会返回一个新的对象。上边提及到的其他方法,我们可以参考这里的教程 Moq’s QuickStart

此外,这个类的增强版是 Match<T>,你完全可以自定义模拟规则。

MockBehavior

这个类用于模拟对象的行为。就像是否按照默认的模式去模拟。让我们进一步看看他的定义:

namespace Moq{// Summary://     Options to customize the behavior of the mock.    public enum MockBehavior    {// Summary://     Causes the mock to always throw an exception for invocations that don't have//     a corresponding setup.        Strict = 0,//// Summary://     Will never throw exceptions, returning default values when necessary (null//     for reference types, zero for value types or empty enumerables and arrays).        Loose = 1,//// Summary://     Default mock behavior, which equals Moq.MockBehavior.Loose.        Default = 1,    }}
复制代码

现在,看看如下例子:

var mock = new Mock<IFake>(MockBehavior.Strict);

指定了mock行为是精准的,如果没有按照预期的Setup就会抛出异常。

MockFactory

这是一个模拟对象的工厂,我们不仅仅可以定制创建模拟对象的配置,也可以成批测试它们。看看下边例子:

var factory = new MockFactory(MockBehavior.Strict) { DefaultValue = DefaultValue.Mock };

// Create a mock using the factory settings

var fooMock = factory.Create<IFake>();

// Create a mock overriding the factory settings

var barMock = factory.Create<IEmailSender>(MockBehavior.Loose);

// Verify all verifiable expectations on all mocks created through the factory

            factory.Verify();
复制代码

在前边,我们已经介绍了传统方式的创建模拟对象,它不会去真正的调用方法,而是仅仅去执行一些假设:如果...那么返回... 。

在下边的例子里,我将继续介绍一些Mock<T> 类中基本并且重要的方法。

Verification

有时候,我们要确定一个方法是否被调用了,或者甚至要知道它被调用了多少次。一个比较传统的方式是使用Verify()方法。看看下边例子:

mock.Verify(foo => foo.DoSomething("Ping"), Times.Once());

上边的代码尝试验证DoSomething("Ping")需要被调用,并且只调用一次。出了Once选项,这里也有更多的选项可供你选择去决定这个方法需要被调用多少次。如: AtLeast, AtLeastOnce, AtMost, AtMostOnce, Between, Equals, Exactly, Never, 和Once

一旦我们已经模拟了对象,验证将是个轻松的任务,看看下边的例子:

   [TestMethod]

public void Test_FindByName_GetCalled()        {

// create some mock data

            IList<Product> products = new List<Product>

{

new Product { ProductId = 1, Name = "C# Unleashed",

            Description = "Short description here", Price = 49.99 },

new Product { ProductId = 2, Name = "ASP.Net Unleashed",

            Description = "Short description here", Price = 59.99 },

new Product { ProductId = 3, Name = "Silverlight Unleashed",

            Description = "Short description here", Price = 29.99 }

};

            Mock<IProductRepository> mock = new Mock<IProductRepository>();

//mock

//.Setup(sender => sender.FindById(It.IsAny<int>()))

//.Returns((int s) => products.Where(

//    x => x.ProductId == s).Single());

            mock.Object.FindById(1);

            mock

            .Verify(x => x.FindById(1), Times.Once());

        }    }
复制代码

在上边的例子里,有两个地方值得注意。

首先是mock.Object.FindById(1)。为了在这个case里让一切变得简单,我们直接调用mock.Object的方法。为什么呢?因为我们这个case只关注这个方法被调用的次数,而不关注返回值。当然,在实际的应用中我们很少这样做。

第二,你有没有注意到被注释掉的句子。它仅仅是一个“如果,那么”句子。意思是说,如果Setup 好了,就返回我们定义的值。

由于调查的时间有限,还有很多关于Mock给力的地方我没有涉及到。我们可以去查看官方的资料。欢迎共同讨论。

参考资料

http://stephenwalther.com/blog/archive/2008/06/12/tdd-introduction-to-moq.aspx

http://code.google.com/p/moq/wiki/QuickStart
http://codeclimber.net.nz/archive/2009/10/23/10-resources-to-learn-moq.aspx
http://blogs.clariusconsulting.net/kzu/tag/moq/

http://blog.miniasp.com/post/2010/09/16/ASPNET-MVC-Unit-Testing-Part-03-Using-Mock-moq.aspx
http://dotnetslackers.com/articles/aspnet/Built-in-Unit-Test-for-ASP-NET-MVC-3-in-Visual-Studio-2010-Part-2.aspx#s4-using-moq-framework

转载于:https://www.cnblogs.com/baiyu/archive/2012/01/11/2319588.html

转使用Moq让单元测试变得更简单相关推荐

  1. 【ASP.Net MVC3 】使用Moq让单元测试变得更简单

    前几天调查完了unity.现在给我的任务是让我调查Moq. 以下是自己找了资料,总结并实践的内容.如果有表述和理解错误的地方.恳请指正. 什么是Moq? Moq(英语发音是Mock-you 或者只是m ...

  2. 项目管理六大制约因素_知道了这7点,软件项目管理会变得更简单!

    软件项目管理,很多产品经理(项目经理)都在吐槽,自己怎么样难以管理,不好做.但是,软件项目管理虽然不易,但是也可以适当把软件项目管理变得更简单,更易于管理.但是需要多做一些管理工作.下面的七点,好好看 ...

  3. 深入解析 Kubebuilder:让编写 CRD 变得更简单

    原文连接:https://developer.aliyun.com/article/719215 作者 | 刘洋(炎寻) 阿里云高级开发工程师 导读:自定义资源 CRD(Custom Resource ...

  4. 快开宝PDA开单器出入库扫码:让批发零售变得更简单

    快开宝PDA开单器出现前 批发商户是这样开单和管理的 ★员工痛苦:需要记客户.价格.库存等等,应对报错价.错漏单.盘错货等各种状况. ★老板麻烦:每天要守店.对单.核账,经常因错漏单.库存乱.积压货. ...

  5. Kafka Streams简介: 让流处理变得更简单

    Introducing Kafka Streams: Stream Processing Made Simple 这是Jay Kreps在三月写的一篇文章,用来介绍Kafka Streams.当时Ka ...

  6. Git 配置别名 —— 让命令变得更简单

    Git 配置别名 -- 让命令变得更简单 卖一下广告,欢迎大家关注我的微信公众号,扫一扫下方二维码或搜索微信号 stormjun,即可关注. 目前专注于 Android 开发,主要分享 Android ...

  7. 菏泽话务员机器人方案_智能打电话机器人让电话营销变得更简单

    原标题:智能打电话机器人让电话营销变得更简单 如今的生活因人工智能的发展而变的越来越好,特别是进入互联网时代,国内客服环境发生了巨大变化,传统的客服体系正在迫捷升级, 智能打电话机器人的到来对应了企业 ...

  8. LEARUN快速开发平台,让开发变得更简单

    互联网时代,程序员一直是一个令人羡慕的高薪职业.但在不久前有人发出了不一样的意见:程序员现在看似乎是一片光明,但AI和人工智能的发展很快,10年后会怎样呢?会不会程序员的工作都被AI替代了?软件编程也 ...

  9. java会变得更简单吗_spring 第一篇(1-1):让java开发变得更简单(下)

    切面(aspects)应用 DI能够让你的软件组件间保持松耦合,而面向切面编程(AOP)能够让你捕获到在整个应用中可重用的组件功能.在软件系统中,AOP通常被定义为提升关注点分离的一个技术.系统由很多 ...

最新文章

  1. HarmonyOS技术特性
  2. signavio-core-components ant build-all-in-one-war failed
  3. Red5 配置RTMPT
  4. RabbitMQ简单队列模式
  5. 编译:ffmpeg,精简ffmpeg.exe
  6. 跨境电商独立站是什么意思?
  7. 关于iframe的一点发现与思考
  8. [note] Homebrew的介绍、安装方法与常用命令整理
  9. python数组对应元素相乘_python – 将一个数组的每一行与numpy中另一个数组的每个元素相乘...
  10. cmd jar java_cmd运行jar报错问题
  11. 【图像分割】基于matlab FCM侧扫声呐图像分割【含Matlab源码 1478期】
  12. jQuery的实用特性扩展类库:jQuery++
  13. 输入框中有内容才激活组件
  14. 科普丨什么是语言?什么是自然语言?
  15. 远程语音 开源_通过开源语音聊天简化远程会议
  16. Android刘海屏、水滴屏全面屏适配详解,997页字节跳动Android面试真题解析火爆全网
  17. 未能找到引用的组件“Microsoft.Office.Core”
  18. 传入的表格格式数据流(TDS)远程过程调用(RPC)协议流不正确。参数 1 (“@xx“): 对于类型特定的元数据,数据类型 0x62 (sql_variant)的类型无效。
  19. 世界各地主流,非主流搜索引擎以及功能性搜索引擎一览
  20. systemctl 设置 frpc 开机自启

热门文章

  1. java oracle database user dsn_跨会话序列化数据库连接
  2. 链队列的基本运算java_链式队列基本操作的实现问题
  3. Arraylist添加5个学生对象,按成绩降序, 删除前三之后的学生
  4. Java中number数字类型的转换_Java下数字类型的转换 (转)
  5. 替换string中的部分字符
  6. 剑指offer:33-37记录
  7. leetcode198 打家劫舍
  8. python源代码现成重用大全
  9. 大数据学习(06)-- 云数据库
  10. 牛客网C++面经 容器和算法