分享

可测试的HttpModule和HttpHandler

 kittywei 2011-05-05

用新的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.  
public abstract class BaseHttpModule : IHttpModule { public void Init(HttpApplication context) { context.BeginRequest += (sender, e) => OnBeginRequest(new HttpContextWrapper(((HttpApplication) sender).Context)); context.Error += (sender, e) => OnError(new HttpContextWrapper(((HttpApplication) sender).Context)); context.EndRequest += (sender, e) => OnEndRequest(new HttpContextWrapper(((HttpApplication) sender).Context)); } public void Dispose() { } public virtual void OnBeginRequest(HttpContextBase context) { } public virtual void OnError(HttpContextBase context) { } public virtual void OnEndRequest(HttpContextBase context) { } }}

如果你的应用程序需要,它能挂起其它事件。现在让我们创建一个基本的从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 (intHttpStatusCode.MovedPermanently;   
  18.             response.Status "301 Moved Permanently";   
  19.             response.RedirectLocation newUrl;   
  20.             response.SuppressContent true;   
  21.             response.End();   
  22.         }   
  23.     }   
  24.  
public class RemoveWwwModule : BaseHttpModule { public override void OnBeginRequest(HttpContextBase context) { const string Prefix = "http://www."; string url = context.Request.Url.ToString(); bool startsWith3W = url.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase); if (startsWith3W) { string newUrl = "http://" + url.Substring(Prefix.Length); HttpResponseBase response = context.Response; response.StatusCode = (int) HttpStatusCode.MovedPermanently; response.Status = "301 Moved Permanently"; response.RedirectLocation = newUrl; response.SuppressContent = true; response.End(); } } }

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./"));   
  21.   
  22.         _httpResponse.SetupSet(response => response.StatusCode (intHttpStatusCode.MovedPermanently);   
  23.         _httpResponse.SetupSet(response => response.Status "301 Moved Permanently");   
  24.         _httpResponse.SetupSet(response => response.RedirectLocation "http:///");   
  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.  
public class RemoveWwwModuleFixture { private readonly Mock<HttpContextBase> _httpContext; private readonly Mock<HttpRequestBase> _httpRequest; private readonly Mock<HttpResponseBase> _httpResponse; public RemoveWwwModuleFixture() { _httpContext = new Mock<HttpContextBase>(); _httpRequest = new Mock<HttpRequestBase>(); _httpResponse = new Mock<HttpResponseBase>(); _httpContext.SetupGet(context => context.Request).Returns(_httpRequest.Object); _httpContext.SetupGet(context => context.Response).Returns(_httpResponse.Object); } [Fact] public void OnBeginRequest_Should_Redirect_When_Requesting_Url_Which_Starts_With_WWW() { _httpRequest.SetupGet(request => request.Url).Returns(new Uri("http://www./")); _httpResponse.SetupSet(response => response.StatusCode = (int) HttpStatusCode.MovedPermanently); _httpResponse.SetupSet(response => response.Status = "301 Moved Permanently"); _httpResponse.SetupSet(response => response.RedirectLocation = "http:///"); _httpResponse.SetupSet(response => response.SuppressContent = true); _httpResponse.Setup(response => response.End()); var module = new RemoveWwwModule(); module.OnBeginRequest(_httpContext.Object); _httpResponse.VerifyAll(); } }}

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.  
public class JavaScriptHandler : BaseHttpHandler { public override void ProcessRequest(HttpContextBase context) { string content = GetContent(); HttpResponseBase response = context.Response; response.ContentType = "application/x-javascript"; response.Write(content); } private string GetContent() { return "YOUR JAVA SCRIPT FILES CONTENT"; } }

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.  
public class JavaScriptHandlerFixture : IDisposable { private readonly Mock<HttpContextBase> _httpContext; private readonly Mock<HttpResponseBase> _httpResponse; private readonly JavaScriptHandler _handler; public JavaScriptHandlerFixture() { _httpContext = new Mock<HttpContextBase>(); _httpResponse = new Mock<HttpResponseBase>(); _httpContext.SetupGet(context => context.Response).Returns(_httpResponse.Object); _handler = new JavaScriptHandler(); } public void Dispose() { _httpResponse.VerifyAll(); } [Fact] public void ProcessRequest_Should_Set_Correct_ContentType() { _httpResponse.SetupSet(response => response.ContentType = "application/x-javascript"); _handler.ProcessRequest(_httpContext.Object); } [Fact] public void ProcessRequest_Should_Write_Content() { _httpResponse.Setup(response => response.Write(It.IsAny<string>())); _handler.ProcessRequest(_httpContext.Object); } }}

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

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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多