众所周知 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. VS选项中没有C#相关设置选项?

    在VS中,行号的设置在工具-选项-文本编辑器,可里面没有VS,我还以为是之前卸载了SP1后造成的. 原来是因为,VS默认环境设置的VB,选项对话框左下角有"显示所有设置"的复选框, ...

  2. 在第一段ionic示例的基础上增加底部导航

    demo2.html <!DOCTYPE html> <html ng-app="app"> <head> <meta charset=& ...

  3. 总想自己动动手系列·3·微信公众号和外网服务交互之通过TOKEN验证(准备篇·1)

    一.准备工作 (1)准备一个微信公众号(对私的订阅号或者对公的服务号). (2)准备一台部署了web应用,并且已经发布出去的Linux服务器(需要说明的是:微信公众号强烈建议使用80端口,使用其他自定 ...

  4. UML学习(二)- 用例图

    UML用例图      用例图主要用来图示化系统的主事件流程,它主要用来描述客户的需求,即用户希望系统具备的完成一定功能的动作,通俗地理解用例就是软件的功能模块,所以是设计系统分析阶段的起点,设计人员 ...

  5. JVM是怎么工作的?

    了解JVM的工作机制能够更好的帮助我们理解java语言本身,规避各种可能的错误.所以,今天趁此机会好好复习一下.来看看JVM是怎么工作的. 一.啥是JVM JVM可以理解为用来运行java程序的一种运 ...

  6. Java 的抽象特性:抽象类与接口深度解析

    要点: 抽象类 接口 抽象类与接口的差别 一. 抽象 对于面向对象编程来说,抽象是它的四大特征之中的一个. 在Java中,能够通过两种形式来体现OOP的抽象:接口和抽象类. 接口和抽象类为我们提供了一 ...

  7. 【laravel54】查看版本号3种方式

    1:最简单的用命令行实现>进入项目目录,执行 > php artisan --version 2:查看文件 vendor\laravel\framework\src\Illuminate\ ...

  8. PHP-数据库长连接mysql_pconnect的细节

    PHP的MySQL持久化连接,美好的目标,却拥有糟糕的口碑,往往令人敬而远之.这到底是为啥么.近距离观察后发现,这家伙也不容易啊,要看Apache的脸色,还得听MySQL指挥. 对于作为Apache模 ...

  9. js--在页面元素上(移动到或获取焦点)、鼠标离开(或失去焦点)

    1.onfocus() 和 onblur() 是一对相反的事件 但是他们只支持一部分标签 W3C关于onblur的描述:http://www.w3school.com.cn/jsref/event_o ...

  10. Python 算法(1) 快速排序

    快速排序(quickSort) 快排的思想:首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序. 百度百 ...