技术开发 频道

使用Abstractions增强ASP.NET应用程序的可测试性

 UrlRewriteModule

 之前都是在测试Http Handler,不过Http Module的测试也较为类似。其原则是相同的:把所有逻辑转发给针对抽象的方法。我们这次就以最最经典的URL重写功能为例,如下:

 public interface IUrlRewriteSource

 {

 string GetRewritePath(string rawUrl);

 }

 public class UrlRewriteModule : IHttpModule

 {

 public void Dispose() { }

 public UrlRewriteModule()

 : this(new RegexUrlRewriteSource(...))

 { }

 internal UrlRewriteModule(IUrlRewriteSource source)

 {

 this.m_source = source;

 }

 private IUrlRewriteSource m_source;

 public void Init(HttpApplication httpApp)

 {

 httpApp.BeginRequest += (sender, e) =>

 {

 HttpContext context = ((HttpApplication)sender).Context;

 this.TryRewritePath(new HttpContextWrapper(context));

 };

 }

 internal void TryRewritePath(HttpContextBase context)

 {

 string newUrl = this.m_source.GetRewritePath(context.Request.RawUrl);

 if (!String.IsNullOrEmpty(newUrl))

 {

 context.RewritePath(newUrl);

 }

 }

 }

 由于测试需要,我们提取出一个IUrlRewriteSource接口。ASP.NET本身会通过无参数的构造函数进行创建,这时就会使用默认的RegexUrlRewriteSource对象。而在测试的时候,就要创建Mock对象并通过构造函数的重载进行“依赖注入”了。在Init方法中我们直接使用匿名委托来作为BeginRequest事件的处理函数,而其中就把逻辑直接委托给TryRewritePath方法了。TryRewritePath方法会判断Source中得知是否需要进行URL重写,并且在需要的时候调用RewritePath方法。它的测试如下:

 [TestMethod]

 public void TryRewritePathTest_No_Rewrite()

 {

 Mock<IUrlRewriteSource> mockSource = new Mock<IUrlRewriteSource>();

 mockSource.Setup(s => s.GetRewritePath(It.IsAny<string>()))

 .Returns<string>(null).Verifiable();

 Mock<HttpContextBase> mockContext = new Mock<HttpContextBase>(MockBehavior.Strict);

 mockContext.Setup(c => c.Request.RawUrl).Returns("Hello");

 mockContext.Setup(c => c.RewritePath(It.IsAny<string>()))

 .Throws(new InvalidOperationException("Should not call the RewritePath method."));

 UrlRewriteModule module = new UrlRewriteModule(mockSource.Object);

 module.TryRewritePath(mockContext.Object);

 mockSource.Verify();

 }

 [TestMethod]

 public void TryRewritePathTest_Rewrite_Article_Detail_Page()

 {

 string rawUrl = "Article/5";

 string targetUrl = "~/Article.aspx?id=5";

 Mock<IUrlRewriteSource> mockSource = new Mock<IUrlRewriteSource>();

 mockSource.Setup(s => s.GetRewritePath(It.IsAny<string>())).Throws(

 new InvalidOperationException("Why so many unnecessary method calls?"));

 mockSource.Setup(s => s.GetRewritePath(rawUrl)).Returns(targetUrl).Verifiable();

 Mock<HttpContextBase> mockContext = new Mock<HttpContextBase>(MockBehavior.Strict);

 mockContext.Setup(c => c.Request.RawUrl).Returns(rawUrl);

 mockContext.Setup(c => c.RewritePath(targetUrl)).Verifiable();

 UrlRewriteModule module = new UrlRewriteModule(mockSource.Object);

 module.TryRewritePath(mockContext.Object);

 mockSource.Verify();

 mockContext.Verify();

 }

 在不需要重写的情况下,IUrlRewriteSource对象的GetRewritePath方法永远返回null,而此时也不应该调用HttpContext的RewritePath方法。否则,便判断给出合适的RawUrl和重写目标,并判断RewritePath方法有没有正确调用过便是。其实单元测试就这么简单。

原文地址:http://www.cnblogs.com/jeffreyzhao/archive/2009/04/23/improve-asp-net-testability-via-abstractions.html

0
相关文章