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()是否被调用过进行验证。

时间: 2024-12-20 15:13:20

Unit Tests Tool - <What is “Mock You”> The introduction to moq #Reprinted#的相关文章

IMPROVING IOS UNIT TESTS WITH OCMOCK

By: Andy Obusek http://engineering.aweber.com/improving-ios-unit-tests-with-ocmock/ OCMock's website: http://ocmock.org/ CocoaPod: https://github.com/CocoaPods/Specs/tree/master/OCMock GitHub page: https://github.com/obuseme/OCMockSample CocoaPod usi

IntelliTest(0) - Introducing Smart Unit Tests[译]

[作者提醒:从Visual Studio 2015 RC 版本开始,"Smart Unit Tests"已经更名为"IntelliTest"] ??关于IntelliTest,有一个短视频,如果你还没看过,强烈建议去看一下.其中介绍了IntelliTest给测试开发带来的新特性,这些新特性将帮助开发者克服在初写单元测试时的惰性.除了视频中所描述的那部分,IntelliTest还包括许多其他特性,这一系列的博客将完善你对整个IntelliTest的知识. ??首先,我

[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 resource requirements. For example, an instantiated object from a class. You will learn how to create the instance of the class one time as a fixture and r

[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 reliable test outcome. Http calls represent such external dependencies. Therefore, when testing our Angular components or services that rely on data ret

ASP.Net MVC3 - The easier to run Unit Tests by moq #Reprinted#

From: http://www.cnblogs.com/techborther/archive/2012/01/10/2317998.html 前几天调查完了unity.现在给我的任务是让我调查Moq. 以下是自己找了资料,总结并实践的内容.如果有表述和理解错误的地方.恳请指正. 什么是Moq? Moq(英语发音是Mock-you 或者只是mock)是一个针对.Net开发的模拟库,它从开始就完全充分利用了.NET3.5(LINQ表达式树)和C#3.0的新特性(lambda表达式).它的目标是让

【翻译】在Visual Studio中使用Asp.Net Core MVC创建你的第一个Web API应用(一)

HTTP is not just for serving up web pages. It's also a powerful platform for building APIs that expose services and data. HTTP is simple, flexible, and ubiquitous. Almost any platform that you can think of has an HTTP library, so HTTP services can re

[Unit Testing] Mock a Node module&#39;s dependencies using Proxyquire

Sometimes when writing a unit test, you know that the module you're testing imports a module that you would like to observe, or at the very least mock to prevent side effects like network activity or file system operations. For JavaScript unit tests

(4.5.4)Android测试TestCase单元(Unit test)测试和instrumentationCase单元测试

Android单元和instrumentation单元测试 Developing Android unit and instrumentation tests Android的单元测试是基于JUnit的.可分为: 1.本地单元测试 - 可以在JVM上运行测试(速度快,优先考虑). 2.Instrumented单元测试 - 需要Android系统 Android的Gradle插件支持在JVM上执行Andr??oid单元测试.它使用特殊版本的android.jar(也称为 Android mocka

Java Unit Testing - JUnit &amp; TestNG

转自https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaUnitTesting.html yet another insignificant programming notes...   |   HOME TABLE OF CONTENTS (SHOW) Java Unit Testing -  & TestNG 1.  Introduction to Unit Testing Framework The various type o