一、概念

  Moq是利用诸如Linq表达式树和Lambda表达式等·NET 3.5的特性,为·NET设计和开发的Mocking库。Mock字面意思即模拟,模拟对象的行为已达到欺骗目标(待测试对象)的效果.
  Moq模拟类类型时,不可模拟密封类,不可模拟静态方法(适配器可解决),被模拟的方法及属性必须被virtual修饰.

二、示例

 //待模拟对象
public interface ITaxCalculate
{
decimal GetTax(decimal rawPrice);
} public class Product
{
public int Id { get; set; } public string Name { get; set; } public decimal RawPrice { get; set; } //目标方法
public decimal GetPriceWithTax(ITaxCalculate calc)
{
return calc.GetTax(RawPrice) + RawPrice;
}
} //单元测试
[TestMethod]
public void TestGetTax()
{
Product product = new Product
{
Id = ,
Name = "TV",
RawPrice = 25.0M
}; //创建Mock对象,反射构建模拟对象空框架
Mock<ITaxCalculate> fakeTaxCalculator = new Mock<ITaxCalculate>(); //模拟对象行为
fakeTaxCalculator.Setup(tax => tax.GetTax(25.0M)).Returns(5.0M); //调用目标方法
decimal calcTax = product.GetPriceWithTax(fakeTaxCalculator.Object); //断言
Assert.AreEqual(calcTax, 30.0M);
}

三、Mock方法

  1. Mock构造方法
    Mock构造方法主要存在两种重载,无参以及传入参数MockBehavior,Mock默认行为:MockBehavior.Loose.
    MockBehavior.Strict:对象行为未设置时调用抛出异常,示例如下.
    MockBehavior.Loose:对象行为未设置时调用不抛出异常,如有必要返回控制,如:0,null.
    MockBehavior.Default:等同于Loose.

     //构造方法
    public Mock();
    public Mock(MockBehavior behavior); //Strict示例
    Mock<IOrder> order = new Mock<IOrder>(MockBehavior.Strict);
    order.Object.ShowTitle(string.Empty);
  2. MockFactory
    Mock工厂,构建MockFactory时传入MockBehavior,通过Create方法创建Mock,次方法类似Mock构造方法.
     MockFactory factory = new MockFactory(MockBehavior.Loose);
    Mock<IOrder> order = factory.Create<IOrder>();
  3. Setup
    模拟对象行为方法,模拟出的方法与原有业务无关
     //模拟接口
    Mock<ICustomer> icustomer = new Mock<ICustomer>();
    //模拟普通方法
    icustomer.Setup(p => p.AddCall());
    icustomer.Setup(p => p.GetCall("Tom")).Returns("Hello"); //模拟含有引用、输出参数方法
    string outString = "";
    icustomer.Setup(p => p.GetAddress("", out outString)).Returns("sz");
    icustomer.Setup(p => p.GetFamilyCall(ref outString)).Returns("xx"); //模拟有返回值方法
    icustomer.Setup(p => p.GetCall(It.IsAny<string>())).Returns((string s) => "Hello " + s); //模拟类
    Mock<Customer> customer = new Mock<Customer>();
    //模拟属性
    customer.Setup(p => p.Name).Returns("Tom");
    Assert.AreEqual("Tom", customer.Object.Name); //另一种方法模拟属性
    customer.SetupProperty(p => p.Name, "Tom2");
    Assert.AreEqual("Tom2", customer.Object.Name); //模拟类方法
    customer.Setup(p => p.GetNameById()).Returns("");
    Assert.AreEqual("", customer.Object.GetNameById());

    It用于添加参数约束,它有以下几个方法:
        Is<T>:匹配给定符合规则的值
        IsAny<T>:匹配给定类型的任何值
        IsRegex<T>:正则匹配
        IsInRange<T>:匹配给定类型的范围

     //对同一个动作可以模拟多个行为,执行动作时,从后往前依次匹配,直到匹配到为止
    var customer = new Mock<ICustomer>();
    customer.Setup(p => p.SelfMatch(It.IsAny<int>())).Returns((int k) => "任何数" + k);
    Console.WriteLine(customer.Object.SelfMatch()); customer.Setup(p => p.SelfMatch(It.Is<int>(i => i % == ))).Returns("偶数");
    Console.WriteLine(customer.Object.SelfMatch()); customer.Setup(p => p.SelfMatch(It.IsInRange<int>(, , Range.Inclusive))).Returns("10以内的数");
    Console.WriteLine(customer.Object.SelfMatch()); Console.WriteLine(customer.Object.SelfMatch());
    Console.WriteLine(customer.Object.SelfMatch()); customer.Setup(p => p.ShowException(It.IsRegex(@"^\d+$"))).Throws(new Exception("不能是数字"));
    customer.Object.ShowException("e1");
  4. Callback
    该方法用于模拟方法执行后回调执行,配合Setup使用
     Mock<ICustomer> customer = new Mock<ICustomer>();
    customer.Setup(p => p.GetCall(It.IsAny<string>()))
    .Returns("方法调用")
    .Callback((string s) => Console.WriteLine("OK " + s));
    customer.Object.GetCall("x");
  5. Throws
    抛出异常,配合Setup使用
     Mock<ICustomer> customer = new Mock<ICustomer>();
    customer.Setup(p => p.ShowException(string.Empty)).Throws(new Exception("参数不能为空!"));
    customer.Object.ShowException("");
  6. Verify、VerifyAll
    验证模拟的方法是否被执行。示例中可通过Verify验证模拟的tax.GetTax(25.0M)是否在Product中被执行
     //Verifiable标记
    Mock<ICustomer> customer = new Mock<ICustomer>();
    customer.Setup(p => p.GetCall(It.IsAny<string>())).Returns("方法调用").Verifiable();
    //若不执行此句代码则验证失败
    customer.Object.GetCall("");
    customer.Verify(); //Verify验证
    customer.Setup(p => p.GetCall());
    customer.Object.GetCall();
    //Verify方法表明该动作一定要在验证之前执行,若调用verify之前都没执行则抛出异常
    customer.Verify(p => p.GetCall()); //添加次数验证
    customer.Object.GetCall();
    customer.Verify(p => p.GetCall(), Times.AtLeast(), "至少应被调用2次"); //验证所有被模拟的动作是否都被执行,无论是否标记为Verifiable
    customer.VerifyAll();
  7. As
    向Mock中条件一个接口实现,只能在对象的属性、方法首次使用之前使用,且参数只能是接口,否则抛出异常。
    之前一直不知道As方法存在有什么意义,虽然调试时监测对象信息可以看到两个Mock之间关联的痕迹,但是一直不知道有什么用,该怎么用,直到今天看到一篇博客...
     public interface IFirstInterface
    {
    int SomeMethodOnFirstInterface();
    } public interface ISecondInterface
    {
    int SomeMethodOnSecondInterface();
    } public interface SomeClassImplementingInterfaces : IFirstInterface, ISecondInterface
    {
    } public class SomeClass
    {
    public static int MultipleInterfaceUser<T>(T x)
    where T : IFirstInterface, ISecondInterface
    {
    IFirstInterface f = (IFirstInterface)x;
    ISecondInterface s = (ISecondInterface)x; return f.SomeMethodOnFirstInterface() + s.SomeMethodOnSecondInterface();
    }
    } //测试代码
    Mock<SomeClassImplementingInterfaces> c = new Mock<SomeClassImplementingInterfaces>(); Mock<IFirstInterface> firstMock = c.As<IFirstInterface>();
    firstMock.Setup(m => m.SomeMethodOnFirstInterface()).Returns(); Mock<ISecondInterface> secondMock = firstMock.As<ISecondInterface>();
    secondMock.Setup(m => m.SomeMethodOnSecondInterface()).Returns(); int returnValue = SomeClass.MultipleInterfaceUser<SomeClassImplementingInterfaces>(c.Object); Assert.AreEqual(returnValue, );

四、参考链接

  • http://blog.csdn.net/alicehyxx/article/details/50667307
  • http://www.cnblogs.com/wintersun/archive/2010/09/04/1818092.html

Moq基础的更多相关文章

  1. Moq基础 判断方法被执行

    如果想知道注入的类的某个方法被使用了几次,就可以通过 mock 提供的方法进行判断方法有没被执行或被使用多少次 本文是一个系列,具体请看 Moq基础(一) 为什么需要单元测试框架 Moq基础(二) 快 ...

  2. 2019-1-29-Moq基础-判断方法被执行

    title author date CreateTime categories Moq基础 判断方法被执行 lindexi 2019-01-29 16:29:57 +0800 2019-01-17 1 ...

  3. 好的框架需要好的 API 设计 —— API 设计的六个原则

    说到框架设计,打心底都会觉得很大很宽泛,而 API 设计是框架设计中的重要组成部分.相比于有很多大佬都认可的面向对象的六大原则.23 种常见的设计模式来说,API 设计确实缺少行业公认的原则或者说设计 ...

  4. 2019-8-31-dotnet-如何在-Mock-模拟-Func-判断调用次数

    title author date CreateTime categories dotnet 如何在 Mock 模拟 Func 判断调用次数 lindexi 2019-08-31 16:55:58 + ...

  5. dotnet 如何在 Mock 模拟 Func 判断调用次数

    在 dotnet 程序有很好用的 Mock 框架,可以用来模拟各种接口和抽象类,可以用来测试某个注入接口的被调用次数和被调用时传入参数.本文告诉大家如何在 Mock 里面模拟一个 Func 同时模拟返 ...

  6. Python之路【第三篇补充】:Python基础(三)

    参考老师:http://www.cnblogs.com/wupeiqi lambda表达式 学习条件运算时,对于简单的 if else 语句,可以使用三元运算来表示,即: # 普通条件语句 if 1 ...

  7. 【PRO ASP.NE MVC4 学习札记】使用Moq辅助进行单元测试

    清楚问题所在: 先开个头,当我们对A进行单元测试时,可能会发现A的实现必须要依赖B.这时,我们在写单元测试时,就必须先创建B的实例,然后把B传给A再建立A的实例进行测试. 这样就会出现一些问题: 1. ...

  8. MOQ

    MOQ:(Minimum order Quantity) 最低订货数量   MOQ 即最小订购量(最小订单量)   对每个产品设定建议订单量是补货的方法之一.另外要注意订单的有效性,这是由供应商制定的 ...

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

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

随机推荐

  1. Entity Framework 6 Recipes 2nd Edition(13-3)译 -> 为一个只读的访问获取实体

    问题 你想有效地获取只是用来显示不会更新的操作的实体.另外,你想用CodeFirst的方式来实现 解决方案 一个非常常见行为,尤其是网站,就是只是让用户浏览数据.大多数情况下,用户不会更新数据.在这种 ...

  2. iOS获取iPhone系统等信息和服务器返回空的异常处理

    前言: 在项目中经常会遇到需要获取系统的信息来处理一些特殊的需求和服务端返回为空的处理,写在这里只是笔记一下. 获取设备的信息 NSLog(@"globallyUniqueString=%@ ...

  3. PHP扩展-生命周期和内存管理

    1. PHP源码结构 PHP的内核子系统有两个,ZE(Zend Engine)和PHP Core.ZE负责将PHP脚本解析成机器码(也成为token符)后,在进程空间执行这些机器码:ZE还负责内存管理 ...

  4. 基于Caffe的Large Margin Softmax Loss的实现(中)

    小喵的唠叨话:前一篇博客,我们做完了L-Softmax的准备工作.而这一章,我们开始进行前馈的研究. 小喵博客: http://miaoerduo.com 博客原文:  http://www.miao ...

  5. 《你不知道的JavaScript》整理(三)——对象

    一.语法 两种形式定义:文字形式和构造形式. //文字形式 var myObj = { key: value }; //构造形式 var myObj = new Object(); myObj.key ...

  6. 读书笔记--SQL必知必会18--视图

    读书笔记--SQL必知必会18--视图 18.1 视图 视图是虚拟的表,只包含使用时动态检索数据的查询. 也就是说作为视图,它不包含任何列和数据,包含的是一个查询. 18.1.1 为什么使用视图 重用 ...

  7. Hadoop入门学习笔记---part4

    紧接着<Hadoop入门学习笔记---part3>中的继续了解如何用java在程序中操作HDFS. 众所周知,对文件的操作无非是创建,查看,下载,删除.下面我们就开始应用java程序进行操 ...

  8. 【分布式】Zookeeper客户端

    一.前言 前篇博客分析了Zookeeper的序列化和通信协议,接着继续学习客户端,客户端是开发人员使用Zookeeper最主要的途径,很有必要弄懂客户端是如何与服务端通信的. 二.客户端 2.1 客户 ...

  9. 利用Python进行数据分析(15) pandas基础: 字符串操作

      字符串对象方法 split()方法拆分字符串: strip()方法去掉空白符和换行符: split()结合strip()使用: "+"符号可以将多个字符串连接起来: join( ...

  10. iOS关于模块化开发解决方案(纯干货)

    关于iOS模块化开发解决方案网上也有一些介绍,但真正落实在在具体的实例却很少看到,计划编写系统文章来介绍关于我对模块化解决方案的理解,里面会有包含到一些关于解耦.路由.封装.私有Pod管理等内容:并编 ...