[转]模拟HttpContext 实现ASP.NET MVC 的单元测试
众所周知 ASP.NET MVC 的一个显著优势即可以很方便的实现单元测试,但在我们测试过程中经常要用到HttpContext,而默认情况下单元测试框架是不提供HttpContext的模拟的,本文通过MOQ框架实现对HttpContext的模拟从而实现更便利的单元测试。
一、Moq框架使用
Moq是一个非常优秀的模拟框架,可以实现对接口成员的模拟,常用在TDD中。 可在此处下载http://code.google.com/p/moq/downloads/list 也可以通过Nuget直接下载。
先来看一个简单的moq应用
1. 定义一个简单接口且不需要实现接口(Moq就是模拟框架因此不需要实现)
1: using System;
2: using System.Collections.Generic;
3: using System.Linq;
4: using System.Text;
5:
6: namespace Stphen.Sample.<a href="http://www.it165.net/pro/webasp/" target="_blank" class="keylink">ASP</a>NETMvc.MockUnitTest.Bussiness
7: {8: public interface IFoo
9: {10: void DoSomeThing(string thingName);
11: bool IsLoveFoo();
12:
13: string FooName { get; set; }14: }
15: }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }2. 在测试代码中我实现了对接口的Mock
1: using System;2: using System.Text;3: using System.Collections.Generic;4: using System.Linq;5: using Microsoft.VisualStudio.TestTools.UnitTesting;6: using Moq;7: using Stphen.Sample.<a href="http://www.it165.net/pro/webasp/" target="_blank" class="keylink">ASP</a>NETMvc.MockUnitTest.Bussiness;8:9: namespace Stephen.Sample.ASPNETMvc.MockUnitTest.TestProject10: {11: [TestClass]12: public class MockUnitTest13: {14: private readonly Mock<IFoo> _fooMock;15:16: public MockUnitTest()17: {18: _fooMock = new Mock<IFoo>();19: }20:21: [TestMethod]22: public void MockDoSomeThingMethodTest()23: {24: _fooMock.Setup(foo => foo.DoSomeThing(It.IsAny<string>())).Callback((string s) => Console.WriteLine(s));25: _fooMock.Object.DoSomeThing("HelloWorld");26: }27:28: [TestMethod]29: public void MockIsLoveMockFramewrokMethodTest()30: {31: _fooMock.Setup(foo => foo.IsLoveFoo()).Returns(true);32: Assert.AreEqual(true, _fooMock.Object.IsLoveFoo());33: }34:35: [TestMethod]36: public void MockFooNamePropertyTest()37: {38: _fooMock.Setup(foo => foo.FooName).Returns("stephen");39: Assert.AreEqual("stephen",_fooMock.Object.FooName);40: }41: }42: }.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
第一个方法没有返回值,第二个有返回值分别用Mock 的 Callback 和 return 方法。
二、通过Moq框架实现HttpContext的模拟(MvcContextMock)
1: using System;2: using System.Collections.Generic;3: using System.Linq;4: using System.Text;5: using System.Web;6: using System.Web.Routing;7: using System.Web.Mvc;8: using Moq;9: namespace MvcContextMock10: {11: /// <summary>12: /// Mvc Context 工厂13: /// </summary>14: public static class MvcContextMockFactory15: {16: private static ControllerContext controllerContext = null;17: /// <summary>18: /// 创建ControllerContext19: /// </summary>20: /// <param name="controller">Controller</param>21: /// <returns></returns>22: public static ControllerContext CreateControllerContext(Controller controller)23: {24: controllerContext = new ControllerContext25: (26: CreateHttpContext(),27: new RouteData(),28: controller);29: return controllerContext;30: }31:32: /// <summary>33: /// 创建ControllerContext34: /// </summary>35: /// <param name="controller">Controller</param>36: /// <param name="contextBase">httpContextBase</param>37: /// <returns></returns>38: public static ControllerContext CreateControllerContext(Controller controller, HttpContextBase contextBase)39: {40: controllerContext = new ControllerContext41: (42: contextBase,43: new RouteData(),44: controller);45: return controllerContext;46: }47:48:49: /// <summary>50: /// 创建ControllerContext51: /// </summary>52: /// <param name="controller">controller</param>53: /// <param name="url">访问的url地址</param>54: /// <param name="httpMethod">访问的方法(get,post)</param>55: /// <param name="name">路由名称</param>56: /// <param name="pattern">路由格式</param>57: /// <param name="obj">路由默认值</param>58: /// <returns></returns>59: public static ControllerContext CreateControllerContext(Controller controller, string url, string httpMethod, string name, string pattern, string obj)60: {61: controllerContext = new ControllerContext62: (63: CreateHttpContext(),64: GetRouteData(url, httpMethod, name, pattern, obj),65: controller);66: return controllerContext;67: }68:69: /// <summary>70: /// 创建ControllerContext71: /// </summary>72: /// <param name="controller">controller</param>73: /// <param name="contextBase">HttpContextBase</param>74: /// <param name="url">访问的url地址</param>75: /// <param name="httpMethod">访问的方法(get,post)</param>76: /// <param name="name">路由名称</param>77: /// <param name="pattern">路由格式</param>78: /// <param name="obj">路由默认值</param>79: /// <returns></returns>80: public static ControllerContext CreateControllerContext(Controller controller, HttpContextBase contextBase, string url, string httpMethod, string name, string pattern, string obj)81: {82: controllerContext = new ControllerContext83: (84: contextBase,85: GetRouteData(url, httpMethod, name, pattern, obj),86: controller);87: return controllerContext;88: }89:90: /// <summary>91: /// 创建HttpContextBase92: /// </summary>93: /// <returns></returns>94: public static HttpContextBase CreateHttpContext()95: {96: var context = new Mock<HttpContextBase>();97: var request = new Mock<HttpRequestBase>();98: var response = new Mock<HttpResponseBase>();99: var session = new Mock<HttpSessionStateBase>();100: var server = new Mock<HttpServerUtilityBase>();101: response102: .Setup(rsp => rsp.ApplyAppPathModifier(Moq.It.IsAny<string>()))103: .Returns((string s) => s);104:105: context.Setup(ctx => ctx.Request).Returns(request.Object);106: context.Setup(ctx => ctx.Response).Returns(response.Object);107: context.Setup(ctx => ctx.Session).Returns(session.Object);108: context.Setup(ctx => ctx.Server).Returns(server.Object);109:110: return context.Object;111: }112:113: #region Private Method114: private static HttpContextBase CreateHttpContext(string url, string httpMethod)115: {116: var context = new Mock<HttpContextBase>();117: var request = new Mock<HttpRequestBase>();118: var response = new Mock<HttpResponseBase>();119: var session = new Mock<HttpSessionStateBase>();120: var server = new Mock<HttpServerUtilityBase>();121: response122: .Setup(rsp => rsp.ApplyAppPathModifier(Moq.It.IsAny<string>()))123: .Returns((string s) => s);124:125: request.Setup(req => req.AppRelativeCurrentExecutionFilePath).Returns(url);126: request.Setup(req => req.HttpMethod).Returns(httpMethod);127:128: context.Setup(ctx => ctx.Request).Returns(request.Object);129: context.Setup(ctx => ctx.Response).Returns(response.Object);130: context.Setup(ctx => ctx.Session).Returns(session.Object);131: context.Setup(ctx => ctx.Server).Returns(server.Object);132:133: return context.Object;134: }135:136: private static RouteData GetRouteData(string url, string httpMethod, string name, string pattern, string obj)137: {138: RouteTable.Routes.MapRoute(name, pattern, obj);139: var routeData =140: RouteTable.Routes.141: GetRouteData(CreateHttpContext(url, httpMethod));142: return routeData;143: }144: #endregion145:146: }147: }.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
三、在mvc中使用MockHttpContextFactory
通过之前编写MvcContextMockFactory类我们在MVC单元测试中可以轻松的实现对HttpContext的模拟
首先创建一个控制器
1: using System;2: using System.Collections.Generic;3: using System.Linq;4: using System.Text;5: using System.Web.Mvc;6: namespace Stephen.Sample.ASPNETMvc.MockUnitTest.Controller7: {8: public class HomeController:System.Web.Mvc.Controller9: {10: public ViewResult Index()11: {12: ViewData["controller"] = RouteData.Values["controller"];13: ViewData["action"] = RouteData.Values["action"];14: return View("Index");15: }16: }17: }.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
因为控制器中需要获取RouteData,RouteData来自于Controller下的ControllerContext
单元测试中调用MockHttpContextFactory模拟ControllerContext,完成单元测试。
1: using System;2: using System.Text;3: using System.Collections.Generic;4: using System.Linq;5: using System.Web.Mvc;6: using Microsoft.VisualStudio.TestTools.UnitTesting;7: using MvcContextMock;8: using Stephen.Sample.ASPNETMvc.MockUnitTest.Controller;9:10: namespace Stephen.Sample.ASPNETMvc.MockUnitTest.TestProject11: {12: [TestClass]13: public class HomeControllerUnitTest14: {15: [TestMethod]16: public void IndexActionTest()17: {18: var homeController = new HomeController();19: homeController.ControllerContext = MvcContextMock.MvcContextMockFactory.CreateControllerContext(homeController, "~/Home/Index", "get", "DefaultRoute", "{controller}/{action}", null);20: ViewResult result= homeController.Index();21: Assert.AreEqual("Index",result.ViewName);22: Assert.AreEqual("Home",result.ViewData["controller"]);23: Assert.AreEqual("Index", result.ViewData["action"]);24: }25: }26: }.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
对于更简单的HttpContext在MockHttpContextFactory中有专用的方法生成与ControllerContext原理类似。
[转]模拟HttpContext 实现ASP.NET MVC 的单元测试的更多相关文章
- ASP.NET MVC之单元测试
ASP.NET MVC之单元测试分分钟的事2014-07-15 13:05 by 书洞里的猫, 550 阅读, 4 评论, 收藏, 编辑 一.为什么要进行单元测试? 大部分开发者都有个习惯(包括本人在 ...
- ASP.NET MVC编程——单元测试
1自动化测试基本概念 自动化测试分为:单元测试,集成测试,验收测试. 单元测试 检验被测单元的功能,被测单元一般为低级别的组件,如一个类或类方法. 单元测试要满足四个条件:自治的,可重复的,独立的,快 ...
- ASP.NET MVC之单元测试分分钟的事
一.为什么要进行单元测试? 大部分开发者都有个习惯(包括本人在内),常常不喜欢去做单元测试.因为我们对自己写的程序总是盲目自信,或者存在侥幸心理每次运行通过后就直接扔给测试组的妹子们了.结果妹子一测, ...
- asp.net mvc 5 单元测试小例子
using System.Collections.Generic; using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTest ...
- asp.net mvc学习(Vs技巧与Httpcontext)
模型绑定分析 博客模拟的表单已经可以包含网站开发过程中遇到的大部分的表单格式了,包含一些数组.对象等等. 1.直接拼接字符串 $.ajax({ url: "/XXX", type: ...
- 一、ASP.NET MVC 路由(一)--- ASP.NET WebForm路由模拟
ASP.NET WebForm 应用,用户请求的是物理文件,其中包括静态页面和动态页面,在Url中的显示都是服务器中一个物理文件的相对路径.但是ASP.NET MVC就不同了,用户请求的是Contro ...
- ASP.NET MVC中HttpContext, HttpContextBase, HttpContextWrapper联系
ttpContext HttpContext是最原始的ASP.NET Context. MVC的目的之一是能够单元测试.HttpContext没有base class,并且不是virtual,所以不能 ...
- 【第三篇】ASP.NET MVC快速入门之安全策略(MVC5+EF6)
目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...
- ASP.NET MVC Model绑定(六)
ASP.NET MVC Model绑定(六) 前言 前面的篇幅对于IValueProvider的使用做个基础的示例讲解,但是没并没有对 IValueProvider类型的实现做详细的介绍,然而MVC框 ...
随机推荐
- hibernate自动生成映射文件
映射文件是O/R Mapping的关键,相当于控制中心.当数据库表较多时,手动配置该映射文件非常耗时.为了快速开发程序,使开发人员的注意力集中到业务逻辑上来,Hibernate官方提供的MiddleG ...
- 编写jquery插件的分享
一.类级别($.extend) 类级别你可以理解为拓展jquery类,最明显的例子是$.ajax(...),相当于静态方法. 开发扩展其方法时使用$.extend方法,即jQuery.extend(o ...
- Cookie存储中文报错:java.lang.IllegalArgumentException: Control character in cookie value or attribute.(转)
项目中做自动登录和保存密码时,Cookie报错Java.lang.IllegalArgumentException,上google查了下 在http://hi.baidu.com/xtxycy/blo ...
- hihoCoder hiho一下 第四十八周 题目1 : 拓扑排序·二
题意: 给定一个拓扑图,其中部分结点含有1个病毒,每个结点只要收到病毒就会立即往出边所能到达的点传播,病毒数可叠加,求所有结点的病毒数总和. 思路: 根据拓扑的特点,每个入度为0的点肯定不会再被传播病 ...
- 学习opengl(起步)
库可以在这里下载 第一个程序: #ifndef GLUT_DISABLE_ATEXIT_HACK #define GLUT_DISABLE_ATEXIT_HACK #endif #include &l ...
- AIX系统管理员--第一章笔记
IBM产品系列 x系类为PC服务器-- e-server x x表示x-architecture 可自由选择运行环境,windows.linux.unix等 p系类为 ...
- Javascript的匿名函数
一.什么是匿名函数?在Javascript定义一个函数一般有如下三种方式:函数关键字(function)语句:function fnMethodName(x){alert(x);}函数字面量(Func ...
- 【进阶——最小费用最大流】hdu 1533 Going Home (费用流)Pacific Northwest 2004
题意: 给一个n*m的矩阵,其中由k个人和k个房子,给每个人匹配一个不同的房子,要求所有人走过的曼哈顿距离之和最短. 输入: 多组输入数据. 每组输入数据第一行是两个整型n, m,表示矩阵的长和宽. ...
- Yii 实现MySQL多库和读写分离
前段时间为SNS产品做了架构设计,在程序框架方面做了不少相关的压力测试,最终选定了YiiFramework,至于为什么没选用公司内部的PHP框架,其实理由很充分,公司的框架虽然是“前辈”们辛苦的积累, ...
- 《C++ primer》--第1,2章小结
来源:http://blog.csdn.net/wangqiulin123456/article/details/8483853 1.变量初始化: 定义变量时,应该给变量赋初始值,除非确定将 ...