用新的System.Web.Abstraction名称空间我们能轻易写出可测试的HttpModule和HttpHandler。在这篇post中, 之前发布的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./")); _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(); } }}
|
|