众所周知 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());

}

http://jiazu.wan128.cn

[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单元测试的更多相关文章

  1. Java反射学习总结终(使用反射和注解模拟JUnit单元测试框架)

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 本文是Java反射学习总结系列的最后一篇了,这里贴出之前文章的链接,有兴趣的可以打开看看. ...

  2. [转]模拟HttpContext 实现ASP.NET MVC 的单元测试

    众所周知 ASP.NET MVC 的一个显著优势即可以很方便的实现单元测试,但在我们测试过程中经常要用到HttpContext,而默认情况下单元测试框架是不提供HttpContext的模拟的,本文通过 ...

  3. Unit Test单元测试时如何模拟HttpContext

    参考文章:http://blog.csdn.net/bclz_vs/article/details/6902638 http://www.cnblogs.com/PurpleTide/archive/ ...

  4. springboot2.0入门(四)----mock模拟测试+单元测试

    一.本节主要记录模拟测试.单元测试: 二.mock 测试 1.1什么是Mock? 在面向对象程序设计中,模拟对象(英语:mock object,也译作模仿对象)是以可控的方式模拟真实对象行为的假的对象 ...

  5. ASP.NET MVC编程——单元测试

    1自动化测试基本概念 自动化测试分为:单元测试,集成测试,验收测试. 单元测试 检验被测单元的功能,被测单元一般为低级别的组件,如一个类或类方法. 单元测试要满足四个条件:自治的,可重复的,独立的,快 ...

  6. 对Controller的单元测试

    在ASP.NET MVC项目的Controller中存在逻辑代码,也需要单元测试.查阅到的资料上,有说ASP.NET MVC框架在设计时便考虑到了满足可测试性,所以相对aspx.Winform来说针对 ...

  7. Asp.Net Core 单元测试正确姿势

    背景 ASP.NET Core 支持依赖关系注入 (DI) 软件设计模式,并且默认注入了很多服务,具体可以参考 官方文档, 相信只要使用过依赖注入框架的同学,都会对此有不同深入的理解,在此无需赘言. ...

  8. Android 单元测试(junit、mockito、robolectric)

    1.运用JUnit4 进行单元测试 首先在工程的 src 文件夹内创建 test 和 test/java 文件夹. 打开工程的 build.gradle(Module:app)文件,添加JUnit4依 ...

  9. Visual Studio 2005 自带单元测试

    一 单元测试简介   单元测试是代码正确性验证的最重要的工具,也是系统测试当中最重要的环节.也是唯一需要编写代码才能进行测试的一种测试方法.在标准的开发过程中,单元测试的代码与实际程序的代码具有同等的 ...

随机推荐

  1. C++ 11 - STL - 函数对象(Function Object) (下)

    1. 预定义函数对象 C++标准库内含许多预定义的函数对象,也就是内置的函数对象. 你可以充分利用他们,不必自己费心去写一些自己的函数对象. 要使用他们,你只要包含如下头文件 #include < ...

  2. Python - 带参数的方法

    import math class Point: def move(self, x, y): self.x = x self.y = y def reset(self): self.move(0, 0 ...

  3. NCBI SRA数据预处理

    SRA数据的的处理流程大概如下 一.SRA数据下载. NCBI 上存储的数据现在大都存储为SRA格式. 下载以后就是以SRA为后缀名. 这里可以通过三种方式下载SRA格式的数据. 1.通过http方式 ...

  4. InnerHtml() 与html( )的区别

    InnerHtml() 与html( )的区别 在一个 HTML 文档中, 我们可以使用 .html() 方法来获取任意一个元素的内容. 如果选择器匹配多于一个的元素,那么只有第一个匹配元素的 HTM ...

  5. taro 打包微信小程序运行失败(二)

    1.报错信息 thirdScriptError sdk uncaught third Error Cannot read property 'dispatch' of null TypeError: ...

  6. mysql 禁制远程连接

    改表法:把host地址改为% use mysql; update user set host = '%' where user = 'root'and host="127.0.0.1&quo ...

  7. JDBC 调用存储过程代码示例

    曾经有过一个两层构架的时代,前台就是界面,后台就是存储过程,存储过程把业务逻辑和数据操作一手包办了. 用存储过程写东西比较复杂,大部分Java程序员或许都对此不太了解,因为我们如今的三层架构使用高级语 ...

  8. 转:RHEL6.3 安装GCC 记录

    本文参考:http://blog.163.com/phys_atom/blog/static/1676445532012229814992/ 如果直接使用GUN GCC官方的源码来安装是不成功的,因为 ...

  9. Maven构建项目时index.jsp文件报错

    错误为:The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path 原 ...

  10. EMQ ---websocket

    简介 近年来随着 Web 前端的快速发展,浏览器新特性层出不穷,越来越多的应用可以在浏览器端或通过浏览器渲染引擎实现,Web 应用的即时通信方式 WebSocket 得到了广泛的应用. WebSock ...