好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

模拟HttpContext 实现ASP.NET MVC 的单元测试

模拟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就是模拟框架因此不需要实现)

View Code

 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();
  12  
 13          string  FooName {  get ;  set  ; }
  14      }
  15  }

  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();
  12  
 13          string  FooName {  get ;  set  ; }
  14      }
  15  }

2. 在测试代码中我实现了对接口的Mock

View Code

 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);
        }
    }
} 

 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的模拟

首先创建一个控制器

View Code

 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  "  );
      }
    }
} 

 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,完成单元测试。

View Code

 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  "  ]);
        }
    }
} 

 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原理类似。

 

分类:  ASP.NET MVC

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于模拟HttpContext 实现ASP.NET MVC 的单元测试的详细内容...

  阅读:54次