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("");

    }

  • 相关阅读:
    学习java集合LinkedHastSet
    学习java,equals方法
    学习java,入门语言java的感概
    学习java哈希值,java入门编程语言
    学习java集合HashSet
    学习java集合set集合
    学习java集合LinkedList
    学习java集合Arraylist
    学习java集合list集合
    学习Java数据结构(入门选Java)
  • 原文地址:https://www.cnblogs.com/gossip/p/2503477.html
Copyright © 2011-2022 走看看