zoukankan      html  css  js  c++  java
  • Moq基础教程

    1 基础概念

    集中精力开发业务逻辑部分,而不想在数据层上花费太多时间,这时,可以通过Mock对象来模拟数据层,而不必去为数据连接,CRUD,Mapping等等去做太多的事,而又可以使业务测试可以进行下去

    2 教程及下载地址

    http://code.google.com/p/moq/

    http://www.codethinked.com/beginning-mocking-with-moq-3-part-1

    http://www.cnblogs.com/jams742003/archive/2010/03/02/1676215.html

    3 一个Demo

    //接口
    public interface ICustomer

    {

    void AddCall();

    string GetCall();

    string GetCall(string strUser);   

      }

    var customer = new Mock<ICustomer>();    //建立Mock对象

    //设置mock调用行为

    customer.Setup(p=>p.AddCall());     

    customer.Setup(p => p.GetCall()).Returns("phone:89898789");

    customer.Setup(p => p.GetCall("Tom")).Returns("Hello");

    //使用mock调用方法

    customer.Object.AddCall();

    Assert.AreEqual("phone:89898789", customer.Object.GetCall());

    Assert.AreEqual("Hello", customer.Object.GetCall("Tom"));

    4 功能点介绍

    4.1 带有引用或输出参数的方法

    string GetAddress(string strUser, out string Address);

    string GetFamilyCall(ref string strUser);

    var customer = new Mock<ICustomer>();

    var outString="oo";

    customer.Setup(p => p.GetAddress("", out outString)).Returns("shijiazhuang");

    customer.Setup(p => p.GetFamilyCall(ref outString)).Returns("xx");

    4.2 调用方法时抛出异常

    方法:void ShowException(string str);

    测试:

    var customer = new Mock<ICustomer>();

    customer.Setup(p => p.ShowException(string.Empty))

    .Throws(new Exception("参数不能为空!"));

    customer.Object.ShowException("");

    4.3 调用时赋值

    方法:void AddCall();

    Mock测试:

    var customer = new Mock<ICustomer>();

    int iCount = 0;

    customer.Setup(p => p.AddCall()).Callback(()=>iCount++);

    Assert.AreEqual(0, iCount);

    customer.Object.AddCall();

    Assert.AreEqual(1, iCount);

    customer.Object.AddCall();

    Assert.AreEqual(2, iCount);

    customer.Object.AddCall();

    Assert.AreEqual(3, iCount);

    4.4 Is<T>:匹配确定的给定类型

    customer.Setup(x => x.SelfMatch(It.Is<int>(i => i % 2 == 0))).Returns("1");

    方法SelfMatch接受int型参数,当参数为偶数时,才返回字符串1。

    4.5 IsAny<T>:匹配给定的任何值

    customer.Setup(p => p.SelfMatch(It.IsAny<int>())).Returns((int k) => "任何数:" + k);

    方法SelfMatch接受int型,且任何int型参数都可以,然后返回:"任何数:" + k。

    这里说明一下Returns方法:

    Returns(Func<TResult>)

    Returns<T>(Func<T,TResult>)

    Returns<T1,T2>(Func<T1,T2,TResult>)

    Returns<T1,T2,T3>(Func<T1,T2,T3,TResult>)

    Returns<T1,T2,T3,T4>(Func<T1,T2,T3,T4,TResult>)

    Returns(TResult)

    4.6 IsInRange<T>:匹配给定类型的范围

    customer.Setup(p => p.SelfMatch(It.IsInRange<int>(0, 10, Range.Inclusive)))

    .Returns("10以内的数");

    方法SelfMatch接受int型,且当范围在[0,10]时,才返回10以内的数

    其中,这个方法,带有一个包含与排除开关。

    4.7 IsRegex<T>:正则匹配

    customer.Setup(p => p.ShowException(It.IsRegex(@"^\d+$")))

    .Throws(new Exception("不能是数字"));

    4.8 设置属性

    public class Customer

    {

    public virtual int Unid { get; set; }

    public virtual string Name { get; set; }

    }

    测试

    var customer = new Mock<Customer>();

    customer.Setup(p => p.Name).Returns("Tom");

    customer.SetupProperty(p => p.Name, "tt");

    4.9 Callbacks回调函数

    当执行某方法时,调用其内部输入的(Action)委托

    看它的5种重载:

    Callback(Action)

    Callback<T>(Action<T>)

    Callback<T1, T2>(Action<T1, T2>)

    Callback<T1, T2, T3>(Action<T1, T2, T3>)

    Callback<T1, T2, T3, T4>(Action<T1, T2, T3, T4>)

    这个方法调用其内部输入的Action委托,Aciton<T>有5种重载,所以这里的Callbacks有5种重载。

    以第二个为例:

    它的定义为:

    ICallbackResult Callback<T>(Action<T> action)

    这个表示一个输入参数,

    var customer = new Mock<ICustomer>();

    customer.Setup(p => p.GetCall(It.IsAny<string>()))

    .Returns("方法调用")

    .Callback((string s)=>Console.WriteLine("ok"+s));

    customer.Object.GetCall("x");

    4.10 Verify 验证

    用于测试mock对象的方法或属性是否被调用执行。当不需要测试结果时用到

    重载很多:

    Verify()

    Verify(Expression<Action<T>>)

    Verify<TResult>(Expression<Func<T, TResult>>)

    Verify(Expression<Action<T>>, Times)

    Verify(Expression<Action<T>>, String)

    Verify<TResult>(Expression<Func<T, TResult>>, Times)

    Verify<TResult>(Expression<Func<T, TResult>>, String)

    Verify(Expression<Action<T>>, Times, String)

    Verify<TResult>(Expression<Func<T, TResult>>, Times, String)

    用其中三个举例

    第一个:Verify(),定义为:

    public void Verify()

    测试

    public void TestVerify()

    {

    var customer = new Mock<ICustomer>();

    customer.Setup(p => p.GetCall(It.IsAny<string>()))

    .Returns("方法调用")

    .Callback((string s) => Console.WriteLine("ok" + s))

    .Verifiable();

    customer.Object.GetCall("调用了!");

    customer.Verify();

    }

    把Mock对象中的GetCall方法设置为可证实的(Verifiable()),

    如果不调用粗体部分语句,那么customer.Verify()执行就不能通过。这个方法很有用。

    第二个:Verify(Expression<Action<T>>),定义为:

    public void Verify(Expression<Action<T>> expression)

    customer.Verify(p => p.GetCall("call"));

    如果没有调用且输入call字串的参数,则失败。

    第三个:Verify(Expression<Action<T>>, Times, String)

    定义:

    public void Verify( Expression<Action<T>> expression,

    Times times,

    string failMessage

    )

    这个比上一个多了两个参数,一个用于表示调用次数相关描述,一个用于失败的时打印信息

    customer.Setup(p => p.GetCall(It.IsAny<string>()))

    .Returns("方法调用")

    .Callback((string s) => Console.WriteLine("ok" + s))

    .Verifiable();

    customer.Object.GetCall("call");

    customer.Object.GetCall("call");

    customer.Verify(p => p.GetCall("call"),

    Times.AtLeast(2),"至少应被调用2次");

    当GetCall方法被调用最少2次(且参数为call)时,测试成功。

    方法中Times是个Times类类型,它有多个方法:

    AtLeast

    AtLeastOnce

    AtMost

    AtMostOnce

    Between

    Exactly

    Never

    Once

    可以从语义上理解它们各自是什么意思,例如:AtLeast的定义为:

    public static Times AtLeast(

    int callCount

    )

    4.11 VerifyAll 验证

    在使用Verify方法时,只有被标记为可证实的(.Verifiable())的才可以验证。

    但VerifyAll会验证所有的调用:

    customer.Setup(p => p.GetCall(It.IsAny<string>()))

    .Returns("方法调用")

    .Callback((string s) => Console.WriteLine("ok" + s));

    customer.Object.GetCall("call");

    customer.VerifyAll();

    4.12 Mock<T> Class

    public class Mock<T> : Mock

    where T : class

    这的构造方法:

    Mock<T>()

    Mock<T>(MockBehavior)

    Mock<T>(array<Object>[])

    Mock<T>(MockBehavior, array<Object>[])

    Mock的泛型实现类,它有很多方法和属性。这里一一列举。

    (一)方法

    (1)As<TInterface>方法

    为mock添加接口实现(mock),可以给它指定设置。

    在mock对象的属性(或方法)首次使用之前才有效。且,参数只能是接口。

    定义:

    public virtual Mock<TInterface> As<TInterface>()

    where TInterface : class

    示例:

    两个接口:

    其中的Icustomer接口还是前几篇中用到的,这里添加一个Iorder接口:

    public interface IOrder

    {

    string ShowTitle(string str);

    }

    Mock测试:

    var customer = new Mock<ICustomer>();

    customer.Setup(p => p.GetCall()).Returns("方法调用");

    customer.Object.GetCall();

    var order=customer.As<IOrder>();

    order.Setup(p => p.ShowTitle(It.IsAny<string>())).Returns("ok");

    Assert.AreEqual("ok",order.Object.ShowTitle(""));

    这个将出现异常,因为在As之前,已经对GetCall进行了调用。

    (2)SetUp方法

    为模拟的对象中的方法指定设置,它有两个重载:

    Setup(Expression<Action<T>>)

    Setup<TResult>(Expression<Func<T,TResult>>)

    从两个委托可以知道,这两个一个是为没有返回值的方法设置,一个是对有返回值的方法设置

    public void TestSetUp()

    {

    var customer = new Mock<ICustomer>();

    customer.Setup(p => p.AddCall())

    .Callback(()=>Console.WriteLine("没有返回值"));

    customer.Setup(p => p.GetCall(It.IsAny<string>()))

    .Returns("ok")

    .Callback((string q) => Console.WriteLine("有返回值"));

    customer.Object.AddCall();

    customer.Object.GetCall("");

    }

  • 相关阅读:
    HDU 1022 Train Problem I
    HDU 1702 ACboy needs your help again!
    HDU 1294 Rooted Trees Problem
    HDU 1027 Ignatius and the Princess II
    HDU 3398 String
    HDU 1709 The Balance
    HDU 2152 Fruit
    HDU 1398 Square Coins
    HDU 3571 N-dimensional Sphere
    HDU 2451 Simple Addition Expression
  • 原文地址:https://www.cnblogs.com/gossip/p/2503477.html
Copyright © 2011-2022 走看看