用新的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
- 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:
- 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:
- 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.mysite.com/"));
- _httpResponse.SetupSet(response => response.StatusCode = (int) HttpStatusCode.MovedPermanently);
- _httpResponse.SetupSet(response => response.Status = "301 Moved Permanently");
- _httpResponse.SetupSet(response => response.RedirectLocation = "http://mysite.com/");
- _httpResponse.SetupSet(response => response.SuppressContent = true);
- _httpResponse.Setup(response => response.End());
- var module = new RemoveWwwModule();
- module.OnBeginRequest(_httpContext.Object);
- _httpResponse.VerifyAll();
- }
- }
HttpHandler
- public abstract class BaseHttpHandler : IHttpHandler
- {
- public virtual bool IsReusable
- {
- get
- {
- return false;
- }
- }
- public void ProcessRequest(HttpContext context)
- {
- ProcessRequest(new HttpContextWrapper(context));
- }
- public abstract void ProcessRequest(HttpContextBase context);
- }
现在让我们创建结合些Javascript文件的HttpHandler,我将在Post中跳过如果是不相关的部分。
- 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:
- 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