Moq MVC 初窥门径(一)

一. 预备知识

        单元测试:单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证

        Mock测试:在测试过程中,对于某些不容易构造或者 不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法

        Lambda表达式

        Linq(Language INtegrated Query)

二. 初识Moq

        Moq(读作“Mock-you”或“Mock”)是.net平台下最有生产力,类型安全和重构友好的mocking库。

        在进行单元测试的时候,经常会碰到这些情景:

        1.想要对业务逻辑层的某个AService方法进行单元测试,而该方法内部却调用了数据链路层的ADataAccess方法,这时候的单元测试,其实已经破坏了单元测试功能点单一的原则,因为AService方法的单元测试首先需要ADataAccesss正常运行。更有甚者,这时候测试环境根本无法连接数据库。

        2.想要对MVC的 Controller层的某AProcess方法进行单元测试,但是该方法内部调用了HttpContext的相关属性或方法。若要进行单元测试,光是模拟Web环境就要花费大量时间。

        而Moq就我们提供了模拟真实对象行为的能力,然后交给被测试功能使用,以此判断被测试功能是否正确。

       注意:Moq只能模拟接口或抽象类。

三. Simple Demo

public interface ITalk

{//简单接口

string Talk();

}

public abstract class Person

{//简单抽象类

public abstract bool IsTalk();

}

class Program

{

static void Main(string[] args)

{

//简单的模拟接口

var iTalk = new Mock<ITalk>();

iTalk.Setup(i => i.Talk()).Returns("Hello,I'm Mock");

Console.WriteLine(iTalk.Object.Talk());

//若该行代码放到iTalk.Object.Talk(),则会引发异常,因为Talk()没有被调用过

iTalk.Verify(i => i.Talk(), Times.AtLeastOnce());

//简单的模拟抽象类

var aPerson = new Mock<Person>();

aPerson.Setup(a=>a.IsTalk()).Returns(false);

Console.WriteLine(aPerson.Object.IsTalk());

Console.ReadLine();

}

}

             F5运行后,效果如下

            image

             上边的例子可以看到,完全没有实现过的接口或者抽象类,可以通过Moq模拟一个虚拟的对象

四. Moq的用法

        Moq中最常用的类分别是

        1.Mock<T> 提供一个模拟实现了T接口(或抽象类)的对象

 

名称

描述

常用方法

Setup (Expression<Action<T>>)

核心方法,通过Lambda设置模拟对象的方法

Verify(Expression<Action<T>> )

核心方法,验证模拟对象方法是否(按照规定的传入参数)执行并通过。该方法有多个重载,分别验证方法执行的次数,失败时的错误消息提示

属性

Object

模拟对象的实例

       2.It 为了使Moq模拟的方法根据不同的传入参数而有不同的行为,Moq提供了该类,可以指定一个传入参数的匹配条件。

 

名称

描述

IsAny< TValue>

匹配给定TValue类型的任何值

IsInRange<TValue>

匹配指定范围的任何值

IsRegex(String)

匹配符合给定正则表达式模式的字符串

五. Moq实战

        回到刚最开始时提到的情景1.

        即数据库访问层没有实现,如何测试业务逻辑层的某个方法是否正确。

        模拟代码如下:

文件1. DataModel

public class DataModel

{

public string Id { get; set; }

}

文件2.IDataAccess

public interface IDataAccess

{

List<DataModel> GetDataModel();

}

文件3IDataModelService

public interface IDataModelService

{

int GetCount();

}

文件4DataAccess

public class DataAccess : IDataAccess

{

public List<DataModel> GetDataModel()

{

return null;

}

}

文件5DataModelService

public class DataModelService : IDataModelService

{

private IDataAccess iDataAccess;

public DataModelService()

{

iDataAccess = new DataAccess();

}

public DataModelService(IDataAccess iData)

{

iDataAccess = iData;

}

public int GetCount()

{

return iDataAccess.GetDataModel().Count;

}

}

测试文件 public class Test

{

static void Main(string[] args)

{

//模拟数据

List<DataModel> lisData = new List<DataModel>() { new DataModel { Id = "1" }, new DataModel { Id = "2" } };

//模拟对象

var data = new Mock<IDataAccess>();

data.Setup(d => d.GetDataModel()).Returns(lisData);

//测试方法

DataModelService dataService = new DataModelService(data.Object);

Console.WriteLine(dataService.GetCount());

Console.ReadLine();

}

}

           运行结果截图:

            image

           情景2:

            有时间做补

六.资料

Moq下载:http://code.google.com/p/moq/ 内含帮助文档

Moq入门:http://www.codethinked.com/post/2009/03/08/Beginning-Mocking-With-Moq-3-Part-1.aspx

http://www.codethinked.com/post/2009/03/10/Beginning-Mocking-With-Moq-3-Part-2.aspx

http://www.codethinked.com/post/2009/03/10/Beginning-Mocking-With-Moq-3-Part-3.aspx

http://www.codethinked.com/post/2009/03/10/Beginning-Mocking-With-Moq-3-Part-4.aspx

原文地址:https://www.cnblogs.com/qiuyeyaozhuai/p/2913983.html