
正文
Unit Tests Tool - <What is “Mock You”> The introduction to moq #Reprinted#
提示:扫一扫查出行【扫一扫了解最新限行尾号】
复制提示
From: http://www.cnblogs.com/wJiang/archive/2010/02/21/1670632.html
Moq即Mock You Framework,故名思意是一个类似Mockery,JMock的Mock框架。 是google上的一个.net开源项目
| 项目扉页 | 相关下载 |
| http://code.google.com/p/moq/ | http://code.google.com/p/moq/downloads/list |
先说说一般的使用Mock进行测试的基本过程:

Moq的3.x版本已经不同以往,这得益于.net3.x为大家带来的Lambda表达式,Linq。
说说Moq的优点:
a.完全开源。开源的好处我就不多说了,不过相比java社区上的活跃,Apache项目的浩繁,.net在这方面确实逊色不少。
b.简单易学,便于使用。Moq的设计原则就是“以极低的门槛获取良好的重构能力”在我个人看来,Moq是我用过的上手最容易使用起来最自然的Mock。
Moq中几个重要的类(在后续文章中详细介绍):
Mock<T>:通过这个类我们能够得到一个Mock<T>对象,T可以是接口 和 类。它有一个公开的Object属性,这个就是我们Moq为我们模拟出的对象。
It:这是一个静态类,用于过滤参数。
MockBehavior:用于配置MockObject的行为,比如是否自动mock。
MockFactory:Mock对象工厂,能够批量生产统一自定义配置的Mock对象,也能批量的进行Mock对象测试。
Match<T>:如果你先嫌It不够用就用Match<T>,通过它能够完全自定义规则。
初识Moq:
新建一个测试,我们用三行代码演示一个Moq的使用。
[TestMethod()]
[Owner(wJiang)]
public void MoqTest0()
{
//make a Mock Object by Moq
var mo = new Mock<TargetInterfaceOne>(); //Setup our Mock Object
mo.Setup(p => p.MethodWithParamAndResult("abc")).Returns("123"); //Assert it!
Assert.AreEqual("123", mo.Object.MethodWithParamAndResult("abc"));
}
说明:
new Mock<T>返回一个Mock对象,我们可以用var接收,这样写起来更方便些,Mock<T>有一个Object属性,存储的就是我们的模拟对象实例。
Setup的参数是一个Lambda Expression,我们可以理解为:“当 被mock的对象p调用MethodWithParamAndResult方法 并且参数为”abc”的时候”。后面再加一个Return(“123”)我们可以理解为:(在之前Setup的情况下)返回的值为”123”。这样,我们就填充好了一个“伪对象”的行为,我们只让它做一件实事儿:当我们调用mo.Object.MethodWithParaAndResult方法并且参数为”abc”时会返回”123”。
实际上我们不仅能够在Setup后面接Returns方法还能接诸如Throws、Verify之类的方法,这是为什么呢?Setup方法会返回一个ISetup对象,看看ISetup的定义:
public interface ISetup<TMock, TResult> : ICallback<TMock, TResult>, IReturnsThrows<TMock, TResult>, IReturns<TMock, TResult>, IThrows, INever, IVerifies, IHideObjectMembers where TMock : class
恩,是链式编程,ISetup接口继承了很多接口,这里我们注意到IReturns<TMock,TResult>,看看IReturns<TMock, TResult>定义:
public interface IReturns<TMock, TResult> : IHideObjectMembers where TMock : class。
里面有一个方法:IReturnsResult<TMock> Returns<T>(Func<T, TResult> valueFunction);
所以我们还能写出这样的代码:
mo.Setup(p => p.MethodWithParamAndResult("abc"))
.Returns("123")
.Callback(……)
.Throws(……)
.Verifiable(……);
呵呵,这种代码理解起来是很自然的。Moq设计的是不是很人性化呢。
上一篇介绍了Moq并给出了一个入门的例子。下面说说Moq中的参数匹配。先看Mock<T>的一个方法。
public ISetup<T> Setup(Expression<Action<T>> expression);
熟悉.NET框架尤其是开发过基于MVVM的WPF应用程序的朋友对Action<T>和Prediect<T>这两个泛型委托应该不陌生,这两个委托的含义很简明,前者表示给定一个参数然后施展一个行为,后者表示施行行为的前提。
假如我们有一个接口IA,IA有一个方法签名string MethodA1(stringidentity)。那么我们怎么模拟一个实现IA接口的对象MethodA1呢?
var mo = new Mock<IA>();
mo.Setup( p => p.MethodA1(“50”)).Return(“Hello, mocker”);
这个例子和上一篇是一样的,这里在额外说明下:Return的参数类型取决于方法的返回类型,如果我们把MethodA1返回void,那么就没法Return方法了,这里由于返回string类型,所以能Return。
当然,方法参数可可选值很多,"51",”52”,”53”,”54”,”55”,”56”……如果我们一个一个的Setup怎么能行?我向大家隆重推出两个类:It,Match<T>。
先说It,It很适合用来匹配数字,字符串参数,它提供了如下几个静态方法(取自Moq的官方API文档):

第一个方法的参数Expression<Predict<TValue>>类型,当你需要某种类型并且这种类型要通过代码来判断的话可以使用它。
第二个方法没有参数,只要是TValue类型的就能匹配成功。
第三个方法用来匹配两个的TValue类型值之间的参数。(Range参数可以设定开闭区间)
第四个是用正则表达式匹配。(仅限于字符串类型参数)
举个例子:
[TestMethod]
[Owner(wJiang)]
public void MoqTest1()
{
var mo = new Mock<TargetInterfaceOne>();
mo.Setup(p => p.MethodWithParamAndResult(It.IsRegex("^God.*$"))).Returns("bless me");
mo.Setup(p => p.MethodWithParamAndResult(It.Is<string>((param => param.IndexOf("Evil") >= 0)))).Returns("away from me");
//mo.Setup(p => p.MethodWithParamAndResult(It.):
Assert.AreEqual("bless me", mo.Object.MethodWithParamAndResult("God comes"));
Assert.AreEqual("away from me", mo.Object.MethodWithParamAndResult("Evil is here"));
}
但是It提供的功能还是显得有些弱,这时候我们可以自定义匹配验证规则。这就用到了Match<T>。
Match<T>是个静态类,它值公开了一个静态方法(重载了两个版本):public static T Create(Predict<T> condition, ……)。
先看下下面的代码便于讲解,我们写个用于参数匹配的静态帮助类。
[TestMethod()]
public void MoqTestA()
{
var mo = new Mock<TargetInterfaceOne>();
mo.Setup(p => p.MethodWithParamAndResult(MatchHelper.CustomMatcher("abc"))).Returns("123"); Assert.AreEqual(mo.Object.MethodWithParamAndResult("abc"), “123); Assert.IsNull(mo.Object.MethodWithParamAndResult(“newyorktimesbyflex”));
}public static class MatchHelper
{
public static string CustomMatcher(string arg)
{
return Match<string>.Create(
p => p.Equals(arg), ()=>null);
} public static IEnumerable<string> Contains(string key)
{
return Match<IEnumerable<string>>.Create(p=>p.Contains(key));
}
}
对我们而言CustomMatcher(string arg)和Contains(string key)就是验证方法。和上个例子比较,就是将p => p.MethodWithParamAndResult(……)里面的东西换成了我们自己的方法。另外一个Contains方法是可用来满足这样一个需求:给定的参数为可迭代类型,只有包含特定的元素时才能匹配
Raise
如果你说会用Setup,那么Raise就更简单了。这里注意下它是无返回值类型。
mockView.Raise(v => v.SelectionChanged += null, new OrderEventArgs { Order = new Order("moq", 500) });
Callback
Callback嘛,顾名思义就是回调。使用Callback可以使我们在某个使用特定参数匹配的方法在被调用时得到通知。比如我们要得知在一次测试中某个方法被调用了几次,可以这么做:
[TestMethod]
public void MoqTest2()
{
var mo = new Mock<TargetInterfaceOne>();
int counter = 0;
mo.Setup(p => p.MethodPure()).Callback( () => counter++ ); mo.Object.MethodPure();
mo.Object.MethodPure(); Assert.AreEqual(2, counter);
}
在这段代码中我们在Setup方法后接了个Callback方法(或者说是调用了ISetup的Callabck方法实现)。这段代码的意思就是在调用MethodPure方法时会执行Callback中的Action委托。
调用两次MethodPure(),测试结果证明确实累加了两次counter。
Verify
有些时候我们并不关注方法的返回结果,而是关注某个方法是不是在内部被调用。
这时我们就用到了Verify/VerifyAll。同时有个有用的类型Times,规定应该调用多少次。如果验证失败则抛出异常。
[TestMethod()] public void MoqTest3()
{
var mo = new Mock<TargetInterfaceOne>();
mo.Setup( p => p.MethodPure() );
mo.Setup( p => p.MethodWithParam("123")).Verifiable("it should be invoked");
//mo.Object.MethodPure();
mo.Object.MethodWithParam("123");
mo.Verify( p => p.MethodPure(), Times.AtLeastOnce() );
mo.Verify(p => p.MethodWithParam("thto"), Times.AtLeastOnce(),
"this method invoking of MethodWithParam() with the parameter: \"thto\" is not happened"); mo.Object.MethodPure();
}
如果在MethodPure前调用mo.Verify(p => p.MethodPure())则会抛出异常,因为不符合条件:在执行verify前至少调用一次。
关于Verify和VerifyAll
这两个方法会对Mock对象的所有Setup过的方法进行验证,那么有什么不同呢?注意到上面代码中绿色字体部分,有一个Verifiable方法,可以理解为为这个Setup的东西加了个验证标记。而Setup(p=>p.MethodPure())时就没有些,那么我们在使用调用Verify()时只会对MethodWithParam(“123”)进行验证而不会对MethodPure()是否被调用过进行验证。
Unit Tests Tool - <What is “Mock You”> The introduction to moq #Reprinted#的更多相关文章- Building Local Unit Tests
If your unit test has no dependencies or only has simple dependencies on Android, you should run you ...
- C# Note37: Writing unit tests with use of mocking
前言 What's mocking and its benefits Mocking is an integral part of unit testing. Although you can run ...
- Unit Tests
The Three Laws of TDD First Law : you may not write production code until you have written a failing ...
- [转]Creating Unit Tests for ASP.NET MVC Applications (C#)
本文转自:http://www.asp.net/mvc/tutorials/older-versions/unit-testing/creating-unit-tests-for-asp-net-mv ...
- [Java in NetBeans] Lesson 07. JavaDoc and Unit Tests
这个课程的参考视频和图片来自youtube. 主要学到的知识点有: 1. organize code into packages Create a package if want to make th ...
- [Python Test] Use pytest fixtures to reduce duplicated code across unit tests
In this lesson, you will learn how to implement pytest fixtures. Many unit tests have the same resou ...
- [Angular + Unit Testing] Mock HTTP Requests made with Angular’s HttpClient in Unit Tests
In a proper unit test we want to isolate external dependencies as much as possible to guarantee a re ...
- Android测试:Building Local Unit Tests
原文:https://developer.android.com/training/testing/unit-testing/local-unit-tests.html 如果你的单元测试没有依赖或者只 ...
- [Unit Testing] Using Mockito Annotations - @Mock, @InjectMocks, @RunWith
Previously we have seen how to do Unit testing with Mockito; import org.junit.Test; import static or ...
随机推荐- Big Clock
Problem Description Our vicar raised money to have the church clock repaired for several weeks. The ...
- [SDOI2008]烧水问题
题目描述 把总质量为1kg的水分装在n个杯子里,每杯水的质量均为(1/n)kg,初始温度均为0℃.现需要把每一杯水都烧开.我们可以对任意一杯水进行加热.把一杯水的温度升高t℃所需的能量为(4200*t ...
- NYOJ 47:过河问题(思维)
47-过河问题 内存限制:64MB 时间限制:1000ms 特判: No 通过数:6 提交数:10 难度:5 题目描述: 在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边.如果不借助手电筒的话 ...
- JComboBox实现当前所选项功能和JFrame窗口释放资源的dispose()方法
JComboBox有一个 SelectedItem属性,所以使用getSelectedItem()就可以得到当前选中值. package ltb20180106; import javax.swing ...
- DNS隧道 iodns
通过iodns这个工具也能搭建DNS隧道 iodns的优点: 对下行数据不进行编码,速度快 支持多平台 最大16个并发连接 强制密码设定 iodns创建的DNS隧道网段不能喝服务器,客户端同一网段,比 ...
- 正则匹配身份证有bug你知道么?
在开发中,我们需要验证用户的输入信息,多半采用正则验证,下面就是身份证证号的几种常用的正则表达式: var reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x) ...
- Android仿新浪新闻SlidingMenu界面的实现 .
先看看原图: 如图所示,这种侧滑效果以另一种方式替代了原先tab导航的那种用户体验方式 给人耳目一新的感觉,现已被广大知名应用所效仿,如新浪新闻,网易新闻,人人网等 那么这种效果该如何实现呢?那就需要 ...
- 检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件时失败解决方案
第一种方法测试过可用:地址:http://download.csdn.net/detail/itjjfamily/8853509 下面是第二种: .NET导出Excel遇到的80070005错误的解决 ...
- Eclipse获取签名证书的SHA1
签名后的获取方式 :http://jingyan.baidu.com/article/3ea51489da3bc252e71bba59.html 未签名的获取方式:http://www.th7.cn/ ...
- AI创投的冰与火之歌:泡沫、跟风、短板和有钱花不出去的沮丧【转】
转自:http://36kr.com/p/5071386.html 国内的AI行业仍处于野蛮生长阶段.热钱不少,优质项目却不多.创业者拿钱难,投资者有钱却花不出去. 编者按:本文来自微信公众号“刺猬公 ...
If your unit test has no dependencies or only has simple dependencies on Android, you should run you ...
前言 What's mocking and its benefits Mocking is an integral part of unit testing. Although you can run ...
The Three Laws of TDD First Law : you may not write production code until you have written a failing ...
本文转自:http://www.asp.net/mvc/tutorials/older-versions/unit-testing/creating-unit-tests-for-asp-net-mv ...
这个课程的参考视频和图片来自youtube. 主要学到的知识点有: 1. organize code into packages Create a package if want to make th ...
In this lesson, you will learn how to implement pytest fixtures. Many unit tests have the same resou ...
In a proper unit test we want to isolate external dependencies as much as possible to guarantee a re ...
原文:https://developer.android.com/training/testing/unit-testing/local-unit-tests.html 如果你的单元测试没有依赖或者只 ...
Previously we have seen how to do Unit testing with Mockito; import org.junit.Test; import static or ...
- Big Clock
Problem Description Our vicar raised money to have the church clock repaired for several weeks. The ...
- [SDOI2008]烧水问题
题目描述 把总质量为1kg的水分装在n个杯子里,每杯水的质量均为(1/n)kg,初始温度均为0℃.现需要把每一杯水都烧开.我们可以对任意一杯水进行加热.把一杯水的温度升高t℃所需的能量为(4200*t ...
- NYOJ 47:过河问题(思维)
47-过河问题 内存限制:64MB 时间限制:1000ms 特判: No 通过数:6 提交数:10 难度:5 题目描述: 在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边.如果不借助手电筒的话 ...
- JComboBox实现当前所选项功能和JFrame窗口释放资源的dispose()方法
JComboBox有一个 SelectedItem属性,所以使用getSelectedItem()就可以得到当前选中值. package ltb20180106; import javax.swing ...
- DNS隧道 iodns
通过iodns这个工具也能搭建DNS隧道 iodns的优点: 对下行数据不进行编码,速度快 支持多平台 最大16个并发连接 强制密码设定 iodns创建的DNS隧道网段不能喝服务器,客户端同一网段,比 ...
- 正则匹配身份证有bug你知道么?
在开发中,我们需要验证用户的输入信息,多半采用正则验证,下面就是身份证证号的几种常用的正则表达式: var reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x) ...
- Android仿新浪新闻SlidingMenu界面的实现 .
先看看原图: 如图所示,这种侧滑效果以另一种方式替代了原先tab导航的那种用户体验方式 给人耳目一新的感觉,现已被广大知名应用所效仿,如新浪新闻,网易新闻,人人网等 那么这种效果该如何实现呢?那就需要 ...
- 检索 COM 类工厂中 CLSID 为 {00024500-0000-0000-C000-000000000046} 的组件时失败解决方案
第一种方法测试过可用:地址:http://download.csdn.net/detail/itjjfamily/8853509 下面是第二种: .NET导出Excel遇到的80070005错误的解决 ...
- Eclipse获取签名证书的SHA1
签名后的获取方式 :http://jingyan.baidu.com/article/3ea51489da3bc252e71bba59.html 未签名的获取方式:http://www.th7.cn/ ...
- AI创投的冰与火之歌:泡沫、跟风、短板和有钱花不出去的沮丧【转】
转自:http://36kr.com/p/5071386.html 国内的AI行业仍处于野蛮生长阶段.热钱不少,优质项目却不多.创业者拿钱难,投资者有钱却花不出去. 编者按:本文来自微信公众号“刺猬公 ...







