模拟HttpContext单元测试
众所周知 ASP.NET MVC 的一个显著优势即可以很方便的实现单元测试,但在我们测试过程中经常要用到HttpContext,而默认情况下单元测试框架是不提供HttpContext的模拟的,本文通过HttpContext的模拟从而实现更便利的单元测试。
一、Moq框架使用
Moq是一个非常优秀的模拟框架,可以实现对接口成员的模拟,常用在TDD中。
先来看一个简单的moq应用
1. 定义一个简单接口且不需要实现接口(Moq就是模拟框架因此不需要实现)
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5
6 namespace Stphen.Sample.ASPNETMvc.MockUnitTest.Bussiness
7 {
8 public interface IFoo
9 {
10 void DoSomeThing(string thingName);
11 bool IsLoveFoo();
13 string FooName { get; set; }
14 }
15 }
2. 在测试代码中我实现了对接口的Mock
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Stphen.Sample.ASPNETMvc.MockUnitTest.Bussiness;
namespace Stephen.Sample.ASPNETMvc.MockUnitTest.TestProject
{
[TestClass]
public class MockUnitTest
{
private readonly Mock<IFoo> _fooMock;
public MockUnitTest()
{
_fooMock = new Mock<IFoo>();
}
[TestMethod]
public void MockDoSomeThingMethodTest()
{
_fooMock.Setup(foo => foo.DoSomeThing(It.IsAny<string>())).Callback((string s) => Console.WriteLine(s));
_fooMock.Object.DoSomeThing("HelloWorld");
}
[TestMethod]
public void MockIsLoveMockFramewrokMethodTest()
{
_fooMock.Setup(foo => foo.IsLoveFoo()).Returns(true);
Assert.AreEqual(true, _fooMock.Object.IsLoveFoo());
}
[TestMethod]
public void MockFooNamePropertyTest()
{
_fooMock.Setup(foo => foo.FooName).Returns("stephen");
Assert.AreEqual("stephen",_fooMock.Object.FooName);
}
}
}
第一个方法没有返回值,第二个有返回值分别用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 MvcContextMock
10 {
11 /// <summary>
12 /// Mvc Context 工厂
13 /// </summary>
14 public static class MvcContextMockFactory
15 {
16 private static ControllerContext controllerContext = null;
17 /// <summary>
18 /// 创建ControllerContext
19 /// </summary>
20 /// <param name="controller">Controller</param>
21 /// <returns></returns>
22 public static ControllerContext CreateControllerContext(Controller controller)
23 {
24 controllerContext = new ControllerContext
25 (
26 CreateHttpContext(),
27 new RouteData(),
28 controller);
29 return controllerContext;
30 }
31
32 /// <summary>
33 /// 创建ControllerContext
34 /// </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 ControllerContext
41 (
42 contextBase,
43 new RouteData(),
44 controller);
45 return controllerContext;
46 }
47
48
49 /// <summary>
50 /// 创建ControllerContext
51 /// </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 ControllerContext
62 (
63 CreateHttpContext(),
64 GetRouteData(url, httpMethod, name, pattern, obj),
65 controller);
66 return controllerContext;
67 }
68
69 /// <summary>
70 /// 创建ControllerContext
71 /// </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 ControllerContext
83 (
84 contextBase,
85 GetRouteData(url, httpMethod, name, pattern, obj),
86 controller);
87 return controllerContext;
88 }
89
90 /// <summary>
91 /// 创建HttpContextBase
92 /// </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 response
102 .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 Method
114 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 response
122 .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 #endregion
145
146 }
147 }
三、在mvc中使用MockHttpContextFactory
通过之前编写MvcContextMockFactory类我们在MVC单元测试中可以轻松的实现对HttpContext的模拟
首先创建一个控制器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
namespace Stephen.Sample.ASPNETMvc.MockUnitTest.Controller
{
public class HomeController:System.Web.Mvc.Controller
{
public ViewResult Index()
{
ViewData["controller"] =
RouteData.Values["controller"];
ViewData["action"] =
RouteData.Values["action"];
return View("Index");
}
}
}
因为控制器中需要获取RouteData,RouteData来自于Controller下的ControllerContext
单元测试中调用MockHttpContextFactory模拟ControllerContext,完成单元测试。
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MvcContextMock;
using Stephen.Sample.ASPNETMvc.MockUnitTest.Controller;
namespace Stephen.Sample.ASPNETMvc.MockUnitTest.TestProject
{
[TestClass]
public class HomeControllerUnitTest
{
[TestMethod]
public void IndexActionTest()
{
var homeController = new HomeController();
homeController.ControllerContext =
MvcContextMock.MvcContextMockFactory.CreateControllerContext(homeController, "~/Home/Index", "get", "DefaultRoute", "{controller}/{action}", null);
ViewResult result=
homeController.Index();
Assert.AreEqual("Index",result.ViewName);
Assert.AreEqual("Home",result.ViewData["controller"]);
Assert.AreEqual("Index", result.ViewData["action"]);
}
}
}
对于更简单的HttpContext在MockHttpContextFactory中有专用的方法生成与ControllerContext原理类似。
模拟HttpContext单元测试的更多相关文章
- Java反射学习总结终(使用反射和注解模拟JUnit单元测试框架)
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 本文是Java反射学习总结系列的最后一篇了,这里贴出之前文章的链接,有兴趣的可以打开看看. ...
- [转]模拟HttpContext 实现ASP.NET MVC 的单元测试
众所周知 ASP.NET MVC 的一个显著优势即可以很方便的实现单元测试,但在我们测试过程中经常要用到HttpContext,而默认情况下单元测试框架是不提供HttpContext的模拟的,本文通过 ...
- Unit Test单元测试时如何模拟HttpContext
参考文章:http://blog.csdn.net/bclz_vs/article/details/6902638 http://www.cnblogs.com/PurpleTide/archive/ ...
- springboot2.0入门(四)----mock模拟测试+单元测试
一.本节主要记录模拟测试.单元测试: 二.mock 测试 1.1什么是Mock? 在面向对象程序设计中,模拟对象(英语:mock object,也译作模仿对象)是以可控的方式模拟真实对象行为的假的对象 ...
- ASP.NET MVC编程——单元测试
1自动化测试基本概念 自动化测试分为:单元测试,集成测试,验收测试. 单元测试 检验被测单元的功能,被测单元一般为低级别的组件,如一个类或类方法. 单元测试要满足四个条件:自治的,可重复的,独立的,快 ...
- 对Controller的单元测试
在ASP.NET MVC项目的Controller中存在逻辑代码,也需要单元测试.查阅到的资料上,有说ASP.NET MVC框架在设计时便考虑到了满足可测试性,所以相对aspx.Winform来说针对 ...
- Asp.Net Core 单元测试正确姿势
背景 ASP.NET Core 支持依赖关系注入 (DI) 软件设计模式,并且默认注入了很多服务,具体可以参考 官方文档, 相信只要使用过依赖注入框架的同学,都会对此有不同深入的理解,在此无需赘言. ...
- Android 单元测试(junit、mockito、robolectric)
1.运用JUnit4 进行单元测试 首先在工程的 src 文件夹内创建 test 和 test/java 文件夹. 打开工程的 build.gradle(Module:app)文件,添加JUnit4依 ...
- Visual Studio 2005 自带单元测试
一 单元测试简介 单元测试是代码正确性验证的最重要的工具,也是系统测试当中最重要的环节.也是唯一需要编写代码才能进行测试的一种测试方法.在标准的开发过程中,单元测试的代码与实际程序的代码具有同等的 ...
随机推荐
- openstack horizon CSS 离线 改动
Openstack horizon 的CSS主要保存在几个文件夹中,各自是horizon/static/dashboard/scss;horizon/openstack_dashboard/stati ...
- 转换和删除重复命令tr
前几篇文章介绍了几个用于处理字符的命令和工具,然而在处理大小写转换.删除重复字符等任务时,这些命令处理起来相对较为麻烦.这里将简单介绍Linux下自带的tr命令,相对于其他命令而言,其语法较为简单,比 ...
- Cg入门21:Fragment shader - 2D纹理採样
体纹理:是啥? tex2D 曾经仅仅能在Fragment程序中纹理採样 UV坐标系:事实上点为左下角,范围为[0,1].U为x轴,V为y轴 watermark/2/text/aHR0cDovL2Jsb ...
- 【LeetCode】68. Text Justification
Text Justification Given an array of words and a length L, format the text such that each line has e ...
- scikit-learn:4.2.3. Text feature extraction
http://scikit-learn.org/stable/modules/feature_extraction.html 4.2节内容太多,因此将文本特征提取单独作为一块. 1.the bag o ...
- Docker入门二
容器管理 1.docker create创建一个容器,但容器并没启动,就和我们创建虚拟机一样,创建了虚拟机后没启动 [root@centos-02 ~]# docker create -it cent ...
- struts2 的国际化
一.使用步骤 1)写资源文件,资源文件名命名规范和之前的讲的一致,有疑问请参考java开发中国际化 2)配置,在 struts.xml 中使用常量进行加载 struts.custom.i18n.res ...
- unity, yield return new WaitForSeconds(waitTime) 在 Time.timeScale=0下卡死
例如下面代码: IEnumerator f(){ Time.timeScale = 0; float waitTime=2; yield return new WaitForSeconds (wait ...
- Genymotion INSTALL_FAILED_CPU_ABI_INCOMPATIBLE
出现这个错误的原因是Genymotion默认的处理器是x86的,不是arm的.所以安装的时候会出错,仅仅要把x86转换成arm就能够了. 转换方法: 1.下载转换的zip文件:X86 to ARM 2 ...
- cadence orcad查找技巧
本文讲述了如何在OrCAD原理图中根据元件位号或者元件值快速查找元件的两种方法. 方法一:在.obj页面的“File”标签下查找元件. 方法二:在.obj页面的“Hierarchy”标签下查找元件. ...