用新的System.Web.Abstraction名称空间我们能轻易写出可测试的HttpModule和HttpHandler。在这篇post中,
我将向你展示如何写可测试的HttpModule和HttpHandler。

之前发布的System.Web.Abstraction的单元测试这些web的基础构件HttpContext的问题。它是密封的,无法用Rhino或Moq来mock.唯一的选择是为这些不能MOCK的对象创建包装对象,但它又有像HttpRequest, HttpResponse, HttpSessionState, HttpServerUtility等。同时这的确是System.Web.Abstraction所提供的,所有包在外面不可mock的HttpContext对象。但是HttpModule 和HttpHandler紧密依赖于原生HttpContext之上,我希望ASP.NET 4.0将改变,直到我们需要创建一个特别层来实现对它的单元测试。

HttpModule

  1. public abstract class BaseHttpModule : IHttpModule   
  2. {   
  3.     public void Init(HttpApplication context)   
  4.     {   
  5.         context.BeginRequest += (sender, e) => OnBeginRequest(new HttpContextWrapper(((HttpApplication) sender).Context));   
  6.         context.Error += (sender, e) => OnError(new HttpContextWrapper(((HttpApplication) sender).Context));   
  7.         context.EndRequest += (sender, e) => OnEndRequest(new HttpContextWrapper(((HttpApplication) sender).Context));   
  8.     }   
  9.   
  10.     public void Dispose()   
  11.     {   
  12.     }   
  13.   
  14.     public virtual void OnBeginRequest(HttpContextBase context)   
  15.     {   
  16.     }   
  17.   
  18.     public virtual void OnError(HttpContextBase context)   
  19.     {   
  20.     }   
  21.   
  22.     public virtual void OnEndRequest(HttpContextBase context)   
  23.     {   
  24.     }   
  25. }  

如果你的应用程序需要,它能挂起其它事件。现在让我们创建一个基本的从url访问的HttpModule:

  1. public class RemoveWwwModule : BaseHttpModule   
  2. {   
  3.     public override void OnBeginRequest(HttpContextBase context)   
  4.     {   
  5.         const string Prefix = "http://www.";   
  6.   
  7.         string url = context.Request.Url.ToString();   
  8.   
  9.         bool startsWith3W = url.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);   
  10.   
  11.         if (startsWith3W)   
  12.         {   
  13.             string newUrl = "http://" + url.Substring(Prefix.Length);   
  14.   
  15.             HttpResponseBase response = context.Response;   
  16.   
  17.             response.StatusCode = (int) HttpStatusCode.MovedPermanently;   
  18.             response.Status = "301 Moved Permanently";   
  19.             response.RedirectLocation = newUrl;   
  20.             response.SuppressContent = true;   
  21.             response.End();   
  22.         }   
  23.     }   
  24. }  

Unit Test:

  1. public class RemoveWwwModuleFixture   
  2. {   
  3.     private readonly Mock<HttpContextBase> _httpContext;   
  4.     private readonly Mock<HttpRequestBase> _httpRequest;   
  5.     private readonly Mock<HttpResponseBase> _httpResponse;   
  6.   
  7.     public RemoveWwwModuleFixture()   
  8.     {   
  9.         _httpContext = new Mock<HttpContextBase>();   
  10.         _httpRequest = new Mock<HttpRequestBase>();   
  11.         _httpResponse = new Mock<HttpResponseBase>();   
  12.   
  13.         _httpContext.SetupGet(context => context.Request).Returns(_httpRequest.Object);   
  14.         _httpContext.SetupGet(context => context.Response).Returns(_httpResponse.Object);   
  15.     }   
  16.   
  17.     [Fact]   
  18.     public void OnBeginRequest_Should_Redirect_When_Requesting_Url_Which_Starts_With_WWW()   
  19.     {   
  20.         _httpRequest.SetupGet(request => request.Url).Returns(new Uri("http://www.mysite.com/"));   
  21.   
  22.         _httpResponse.SetupSet(response => response.StatusCode = (int) HttpStatusCode.MovedPermanently);   
  23.         _httpResponse.SetupSet(response => response.Status = "301 Moved Permanently");   
  24.         _httpResponse.SetupSet(response => response.RedirectLocation = "http://mysite.com/");   
  25.         _httpResponse.SetupSet(response => response.SuppressContent = true);   
  26.         _httpResponse.Setup(response => response.End());   
  27.   
  28.         var module = new RemoveWwwModule();   
  29.   
  30.         module.OnBeginRequest(_httpContext.Object);   
  31.   
  32.         _httpResponse.VerifyAll();   
  33.     }   
  34. }  

HttpHandler

  1. public abstract class BaseHttpHandler : IHttpHandler   
  2. {   
  3.     public virtual bool IsReusable   
  4.     {   
  5.         get  
  6.         {   
  7.             return false;   
  8.         }   
  9.     }   
  10.   
  11.     public void ProcessRequest(HttpContext context)   
  12.     {   
  13.         ProcessRequest(new HttpContextWrapper(context));   
  14.     }   
  15.   
  16.     public abstract void ProcessRequest(HttpContextBase context);   
  17. }  

现在让我们创建结合些Javascript文件的HttpHandler,我将在Post中跳过如果是不相关的部分。

  1. public class JavaScriptHandler : BaseHttpHandler   
  2. {   
  3.     public override void ProcessRequest(HttpContextBase context)   
  4.     {   
  5.         string content = GetContent();   
  6.         HttpResponseBase response = context.Response;   
  7.   
  8.         response.ContentType = "application/x-javascript";   
  9.         response.Write(content);   
  10.     }   
  11.   
  12.     private string GetContent()   
  13.     {   
  14.         return "YOUR JAVA SCRIPT FILES CONTENT";   
  15.     }   
  16. }  

Unit Test:

  1. public class JavaScriptHandlerFixture : IDisposable   
  2. {   
  3.     private readonly Mock<HttpContextBase> _httpContext;   
  4.     private readonly Mock<HttpResponseBase> _httpResponse;   
  5.   
  6.     private readonly JavaScriptHandler _handler;   
  7.   
  8.     public JavaScriptHandlerFixture()   
  9.     {   
  10.         _httpContext = new Mock<HttpContextBase>();   
  11.         _httpResponse = new Mock<HttpResponseBase>();   
  12.   
  13.         _httpContext.SetupGet(context => context.Response).Returns(_httpResponse.Object);   
  14.   
  15.         _handler = new JavaScriptHandler();   
  16.     }   
  17.   
  18.     public void Dispose()   
  19.     {   
  20.         _httpResponse.VerifyAll();   
  21.     }   
  22.   
  23.     [Fact]   
  24.     public void ProcessRequest_Should_Set_Correct_ContentType()   
  25.     {   
  26.         _httpResponse.SetupSet(response => response.ContentType = "application/x-javascript");   
  27.   
  28.         _handler.ProcessRequest(_httpContext.Object);   
  29.     }   
  30.   
  31.     [Fact]   
  32.     public void ProcessRequest_Should_Write_Content()   
  33.     {   
  34.         _httpResponse.Setup(response => response.Write(It.IsAny<string>()));   
  35.   
  36.         _handler.ProcessRequest(_httpContext.Object);   
  37.     }   
  38. }  

如果你要看更多的可单元测试HttpModule and HttpHandler,到KiGG源代中查看吧。

翻译:Petter Liu   http://wintersun.cnblogs.com   原文:Source

posted on 2009-03-14 21:33  PetterLiu  阅读(1007)  评论(0编辑  收藏  举报