Asp.net MVC 单元测试 简要笔记

首先要啰嗦几句。

单元测试是TDD的重要实践方法,也是代码质量的一种保证手段。在项目的工程化开发中,研发人员应该尽量保证书写Unit Test,即使不使用TDD。

(VS中,我们可以直接使用微软提供的一套单元测试框架,一般使用足够了,特别需求的话,可以使用其他更好的框架。)

书写单元测试时,我们并不一定真的要去连接数据库,毕竟就算只使用自己计算机上的研发数据库,也不能保证数据正确性和完备性,毕竟自己经常会操作些垃圾数据。

这个时候就需要模拟一个“数据库”来构造我们想要的一些数据。这个就是Mock最直接的需求。然后当我们进一步实践,会发现我们的Service层等,也可以用Mock模拟对象,而不是非要去new一个真实对象。真实场景是当我们研发小组合作时,你作为更高层的研发人员,可能只拿到了服务层的接口,具体的实现类你的同事还在研发中,这个时候你要做Unit Test,就只有模拟一个假的Service实现了。

C#的单元测试框架中,有一套Mock框架就叫Moq。

Moq可以直接在VS 2013及以后的版本中通过Nuget获取。以前的版本的VS可以到github上下载Moq的dll。

Moq的github地址为:Moq

Moq的QuickStart页面为:QuickStart 深入学习,可以直接看此文档。

MVC中,最直接需要模拟的应该就是HttpContext相关对象,如HttpRequest、Server、Session等对象。以HttpRequest为例。

首先,我们要知道, controller中相关HttpContext的对象是ControllerContext,它就是HttpContextBase。模拟的HttpContext通过它绑定给Controller。

controller.ControllerContext = new ControllerContext(mockContext.Object, new RouteData(), controller);

mockContext.Object就是我们用Moq模拟的HttpContextBase。

这里是绑定的代码,倒推回去,我们应该先生成mockContext,如下:

private Mock<HttpContextBase> mockContext = new Mock<HttpContextBase>();

实际我们代码可能使用的是Request["xxx"]、Session["yyy"],这些对象又依赖于HttpContextBase,所以我们需要模拟它们,然后绑定到 mockContext。如下

 var mockRequest = new Mock<HttpRequestBase>();
            //模拟Request["xxx"]
            if (dataIndexed != null)
            {
                foreach (var pair in dataIndexed)
                {
                    mockRequest.Setup(x => x[pair.Key]).Returns(pair.Value);
                }
            }
mockContext.SetupGet(x => x.Request).Returns(mockRequest.Object);

 注意最后一句就是将模拟的Request绑定到模拟的HttpContextBase上。代码含义是:当通过mockContext.Request(即它的get方法)得到Request对象时,把mockRequest模拟的HttpRequest对象返回。 

Moq的方法都是比较直白的含义,如上就是:SetupGet(x => x.Request).Returns($$$),针对对象Request使用Get方法时,Returns相应的对象$$$。其他的对象,不管是HttpContextBase的还是Request的再子层对象,都通过这样的方法设置,前提是相应的类中有此属性(get,set)。

回过头继续看上面代码这段mockRequest.Setup(x => x[pair.Key]).Returns(pair.Value); 这个就是直接针对值进行设置,这里是针对类的Indexedr进行设置。

还有一些其他方法,需要时就看QuickStart了。

另外,针对全局的HttpContext对象,在单元测试中,它是null的,所以为了保证单元测试可进行,需要对其进行包装,在项目中使用包装的类进行访问。这样,单元测试时,就注入自己模拟的HttpContext对象。然而HttpContext是sealed类,是不能被Mock的。所以我们可以在包装类中,使用两个对象,分别指向Mock的对象和真实的HttpContext,依据是否模拟的判断在代码中选择调用。也可以使用HttpContextWrapper来包装HttpContext,因为HttpContextWrapper是HttpContextBase的实现。如:

 /// <summary>
    /// 全局HttpContext的包装类,以便单元测试
    /// </summary>
    public class CmsHttpContext
    {
        /// <summary>
        /// 当前单例对象
        /// </summary>
        private static CmsHttpContext _instance = new CmsHttpContext();
        /// <summary>
        ///  包装的HttpContext
        /// </summary>
        private static HttpContextBase wrapper = null;
        /// <summary>
        /// 是否被包装
        /// </summary>
        private static bool IsWrap = false;

        private CmsHttpContext()
        {

        }
        /// <summary>
        /// 当前HttpContext对象
        /// </summary>
        public static HttpContextBase Current
        {
            get
            {
                if (!IsWrap)
                {
                    wrapper = new HttpContextWrapper(HttpContext.Current);
                }
                return wrapper;
            }
        }

        /// <summary>
        /// 包装外部 HttpContext,仅用于单元测试中
        /// </summary>
        /// <param name="context"></param>
        public static void Wrap(HttpContextBase context)
        {
            IsWrap = true;
            wrapper = context;
        }
    }

 其他要注意的点:

1.Action的方法直接调用即可以执行。针对ViewBag.XXX,使用Controller对象调用,如mController.ViewBag.XXX

2.JsonResult中Json(XXX),如果XXX是动态类型的话,它在传输后会变成object,单元测试中无法识别它相应的属性,可以使用框架ExposedObject(Nuget中可以直接下载)进行包装,将其包装回dynamic进行测试,如下:

var jsonData = Exposed.From(result.Data);

            Assert.IsTrue(jsonData.total > 0);
            Assert.IsTrue(jsonData.list.Count > 0);

  

时间: 2024-08-04 20:45:49

Asp.net MVC 单元测试 简要笔记的相关文章

学习ASP.NET MVC框架揭秘笔记目录

学习ASP.NET MVC框架揭秘笔记目录 第一章     ASP.NET+MVC 1.1传统的MVC模式 持续更新中,,,,

学习ASP.NET MVC框架揭秘笔记-IIS/ASP.NET管道(一)

IIS/ASP.NET管道 ASP.NET MVC就是建立在ASP.NET平台基础上基于MVC模式的Web应用框架,深入理解ASP.NET MVC的前提是对ASP.NET管道式设计有深刻的认识.由于ASP.NET Web应用大都寄宿于IIS上,接下来会介绍3个主要的IIS版本对各自Web请求的处理方式. 1.3.1 IIS 5.x与ASP.NET IIS 5.x运行在进程InetInfo.exe中,该进程寄宿着一个名为World WideWeb Publishing Service(简称W3SV

asp.net MVC 小白的笔记-说下这几天学习mvc的经历

到现在才来学习mvc,算是有点晚了,接触的比较晚! 首先是接触到了基础的EF,先说下EF,EF是一种ORM(实体映射对象)框架,是基于ado.net的一种开发更便捷的对数据库进行的技术,有2种开发,一种是ModelFirst,就是 先通过新建ado模型,把数据库中的表直接映射到项目中的模型视图 , 该模型视图下有数据库中的各种字段,并且这些字段会自动生成一个类,映射成一个实体类.还有另外一种就是CodeFirst,顾名思义 就是先写代码,建视图,根据所建的视图,视图之间的关系,关系这里有一个非常

学习ASP.NET MVC框架揭秘笔记-传统MVC模式

1.1传统MVC模式 对于大部分面向最终用户的应用来说,他们都需要具有一个与用户进行交互的可视化UI界面,我们将这个UI称为视图(View).在早期,我们倾向于将所有与UI相关的操作糅合在一起,这些操作包括UI界面的呈现.用户交互操作的捕捉与响应.业务流程的执行及对数据的存取等,我们将这种设计模式称为自治视图(Autonomuous View  ,  AV). 1.1.1  自治视图 1.1.2  什么是MVC模式

学习ASP.NET MVC框架揭秘笔记-自治视图

1.1.1自治视图 一个典型的人机交互应用具有3个主要的关注点,既数据在可视化界面上的呈现.UI处理逻辑(用于处理用户交互式操作的逻辑)和业务逻辑.自治视图模式将三者混合在一起,势必会带来如下一些问题. 1.重用性.业务逻辑是与UI无关的,应该最大限度地被重用,但是若将业务逻辑定义在自治视图中相当于使他完全与视图本身绑定在一起.除此之外,如果我们能够将UI的行为抽象出来,基于抽象化UI的处理逻辑也是可以被共享的,但是定义在自治视图中的UI处理逻辑也完全丧失了重用的可能. 2.稳定性.业务逻辑具有

学习ASP.NET MVC框架揭秘笔记-什么是MVC模式

1.1.2什么是MVC模式 MVC的创建者是Trygve M.H.Reenskau,他是挪威的计算机专家,同时也是奥斯陆大学的名誉教授.MVC是他在1979年提出的一种主要针对GUI应用的软件架构模式. MVC体现了"关注点分离"这一基本的设计方针,他将一个人机交互应用设计的功能分为Model.Controller和View三部分,他们各自具有如下的职责. 1.Model是对应用状态和业务逻辑的封装,我们可以将它理解为同时包含数据和行为的领域模型.Model接受Controller的请

学习ASP.NET MVC框架揭秘笔记-实例演示:SC模式的应用

实例演示:SC模式的应用 为了对SC模式下的MVP,尤其是该模式下的View和Presenter之间的交互方式有一个深刻的认识,我们现在来做一个实例演示.我们采用员工查询的场景,用ASP.NET Web Forms来建立这个简单的应用. 我们先来定义员工的数据类型,Employee来表示一个员工,有5个属性:ID.姓名.性别.出生日期和部门. public class Employee { public string Id { get; private set; } public string

学习ASP.NET MVC框架揭秘笔记-MVP

1.2.1                      MVP MVP是一种UI架构模式,适用于基于事件驱动的应用框架.MVP中的M和V分别对应MVC的Model和View,而P(Presenter)代替了Controller. 在MVP模式中,能够与Model直接进行交互的仅限于Presenter,View只能通过Presenter间接地调用Model.Model的独立性在这里得到真正的体现,他不仅仅与可视化元素的呈现无关,与UI处理逻辑(Presenter)也无关. MVP不仅仅避免了View

学习ASP.NET MVC框架揭秘笔记-IIS/ASP.NET管道(二)

IIS7.0与ASP.NET IIS7.0在请求的监听和分发机制上又进行了革新性的改进,主要体现在引入Window进程激活服务(Windows Process Activation Service,WAS)分流了原来(IIS6.0)W3SVC承载的部分功能.IIS6.0中W3SVC主要承载着如下三大功能. 1.HTTP请求接收:接收HTTP.SYS监听到的HTTP请求. 2.配置管理:从元数据库(metabase)中加载配置信息对相关组件进行配置. 3.进程管理:创建.回收.监控工作进程. II