[翻譯] ASP.NET MVC Tip #13 – 對自訂路由進行單元測試

來源:互聯網
上載者:User
[翻譯] ASP.NET MVC Tip #13 – 對自訂路由進行單元測試

原文地址:http://weblogs.asp.net/stephenwalther/archive/2008/07/02/asp-net-mvc-tip-13-unit-test-your-custom-routes.aspx

翻譯:Anders Liu

摘要:在這個Tip中,Stephen Walther示範了如何為你的ASP.NET MVC應用程式中的自訂路由建立單元測試。Stephen Walther介紹了如何測試一個URL是否被映射到正確的控制器、控制器操作和巨集指令引數上。

在建立ASP.NET MVC應用程式時,如果你是忠於測試驅動開發的,你應該對所有東西進行單元測試。先編寫單元測試,再編寫代碼來滿足測試。重複、重複、重複到吐。

路由是MVC應用程式中的重要部分。路由決定了一個URL如何映射到特定的控制器和控制器操作。由於路由在MVC應用程式中如此重要,所以你需要為路由編寫單元測試。在這個Tip中,我將向你展示如何通過仿製HTTP Context來為路由編寫單元測試。

建立路由表

你可以在Global.asax檔案中為MVC應用程式建立路由。換句話說,它們是定義在GlobalApplication類中的。清單1包含了預設的Global.asax檔案。

清單1 - Global.asax

<br />using System;<br />using System.Collections.Generic;<br />using System.Linq;<br />using System.Web;<br />using System.Web.Mvc;<br />using System.Web.Routing;</p><p>namespace DefaultOne<br />{<br /> public class GlobalApplication : System.Web.HttpApplication<br /> {<br /> public static void RegisterRoutes(RouteCollection routes)<br /> {<br /> routes.IgnoreRoute("{resource}.axd/{*pathInfo}");</p><p> routes.MapRoute(<br /> "Default", // Route name<br /> "{controller}/{action}/{id}", // URL with parameters<br /> new { controller = "Home", action = "Index", id = "" } // Parameter defaults<br /> );</p><p> }</p><p> protected void Application_Start()<br /> {<br /> RegisterRoutes(RouteTable.Routes);<br /> }<br /> }<br />}<br />

預設情況下,一個路由包括名字、路徑和預設路由。路由得到一個URL後會將其中的不同片段映射到特定的控制器、控制器操作和傳遞給操作的參數上。如:

  • /Customer/Details/23

    • Controller = Customer
    • Action = Details
    • Id = 23

URL中的第一個片段被映射到控制器名字,第二部分被映射到控制器操作,而最後一部分被映射到名字為Id的參數。

Default路由包含了預設值。如果沒有指定控制器,則使用Home控制器。如果沒有指定操作,則調用Index操作。如果沒有指定Id,則傳第一個Null 字元串。因此,下面的URL將被這樣解釋:

  • /

    • Controller = Home
    • Action = Index
    • Id = ""

對很多MVC應用程式來說,預設路由是你經常要用到的一個。然而,你還可以選擇建立自訂路由。例如,清單2中的Global.asax檔案包含了兩個自訂路由。

清單2 - Global.asax

<br />using System;<br />using System.Collections.Generic;<br />using System.Linq;<br />using System.Web;<br />using System.Web.Mvc;<br />using System.Web.Routing;</p><p>namespace Tip13<br />{<br /> public class GlobalApplication : System.Web.HttpApplication<br /> {<br /> public static void RegisterRoutes(RouteCollection routes)<br /> {<br /> routes.IgnoreRoute("{resource}.axd/{*pathInfo}");</p><p> // Route for blog archive<br /> routes.MapRoute(<br /> "Archive", // Name<br /> "Archive/{entryDate}", // URL<br /> new { controller = "Blog", action = "Details" }, // Defaults<br /> new { entryDate = @"\d{2}-\d{2}-\d{4}" } // Constraints<br /> );</p><p> // Default route<br /> routes.MapRoute(<br /> "Default", // Name<br /> "{controller}/{action}/{id}", // URL<br /> new { controller = "Home", action = "Index", id = "" } // Defaults<br /> );</p><p> // Catch all route<br /> routes.MapRoute(<br /> "CatchIt", // Name<br /> "Product/{*values}", // URL<br /> new { controller = "Product", action = "Index" } // Defaults<br /> );</p><p> }</p><p> protected void Application_Start()<br /> {<br /> RegisterRoutes(RouteTable.Routes);<br /> }<br /> }<br />}<br />

清單2中修改過的Global.asax包含了一個新的、名為Archive的路由,用於處理類似下面這樣的對blog文章的請求:

  • /archive/12-25-1966

該自訂路由將這個URL映射到名為Blog的控制器並調用Details()操作。日期將作為名為entryDate的參數傳遞到Details()操作。

這個Global.asax檔案還定義了一個catchall路由。catchall路由包含任意數量的片段。例如,catchall路由將會匹配:

  • /Product/a
  • /Product/a/b
  • /Product/a/b/c

以此類推。

對自訂路由進行單元測試

那麼如何測試自訂路由呢?在我從xUnit(http://www.codeplex.com/xUnit)中看到一個MVC單元測試樣本之前我無法指出如何做這樣的單元測試。為了測試自訂路由,你需要仿製HTTP Context。

在上一篇Tip中,我介紹了在對ASP.NET內部對象如工作階段狀態、表單參數和使用者實體/角色進行單元測試時,如何仿製內容物件。如果你還沒有讀過這篇Blog,請訪問下面的頁面:

  • http://www.cnblogs.com/AndersLiu/archive/2008/07/26/asp-net-mvc-tip-12-faking-the-controller-context.html

在看過了xUnit的樣本之後,我修改了仿製的內容物件,使其能夠用於對路由進行單元測試。清單3中的單元測試示範了如何對清單2中的Global.asax中包含的自訂路由進行測試。

清單3 - RouteTest.cs

<br />using System;<br />using System.Web.Routing;<br />using Microsoft.VisualStudio.TestTools.UnitTesting;<br />using MvcFakes;<br />using Tip13;</p><p>namespace Tip13Tests.Routes<br />{<br /> [TestClass]<br /> public class RoutesTest<br /> {<br /> [TestMethod]<br /> public void TestDefaultRoute()<br /> {<br /> // Arrange<br /> var routes = new RouteCollection();<br /> GlobalApplication.RegisterRoutes(routes);</p><p> // Act<br /> var context = new FakeHttpContext("~/");<br /> var routeData = routes.GetRouteData(context);</p><p> // Assert<br /> Assert.AreEqual("Home", routeData.Values["controller"], "Default controller is HomeController");<br /> Assert.AreEqual("Index", routeData.Values["action"], "Default action is Index");<br /> Assert.AreEqual(String.Empty, routeData.Values["id"], "Default Id is empty string");<br /> }</p><p> [TestMethod]<br /> public void TestGoodArchiveRoute()<br /> {<br /> // Arrange<br /> var routes = new RouteCollection();<br /> GlobalApplication.RegisterRoutes(routes);</p><p> // Act<br /> var context = new FakeHttpContext("~/Archive/12-25-1966");<br /> var routeData = routes.GetRouteData(context);</p><p> // Assert<br /> Assert.AreEqual("Blog", routeData.Values["controller"], "Controller is Blog");<br /> Assert.AreEqual("Details", routeData.Values["action"], "Action is Details");<br /> Assert.AreEqual("12-25-1966", routeData.Values["entryDate"], "EntryDate is date passed");</p><p> }</p><p> [TestMethod]<br /> public void TestBadArchiveRoute()<br /> {<br /> // Arrange<br /> var routes = new RouteCollection();<br /> GlobalApplication.RegisterRoutes(routes);</p><p> // Act<br /> var context = new FakeHttpContext("~/Archive/something");<br /> var routeData = routes.GetRouteData(context);</p><p> // Assert<br /> Assert.AreNotEqual("Blog", routeData.Values["controller"], "Controller is not Blog");<br /> }</p><p> [TestMethod]<br /> public void TestCatchAllRoute()<br /> {<br /> // Arrange<br /> var routes = new RouteCollection();<br /> GlobalApplication.RegisterRoutes(routes);</p><p> // Act<br /> var context = new FakeHttpContext("~/Product/a/b/c/d");<br /> var routeData = routes.GetRouteData(context);</p><p> // Assert<br /> Assert.AreEqual("a/b/c/d", routeData.Values["values"], "Got catchall values");<br /> }<br /> }<br />}<br />

這是Visual Studio Test(MS Test)單元測試。當然你也可以使用不同的測試架構,如NUnit或xUnit。下面是這個單元測試工作的方式。

首先,建立了一個路由集合,並將其傳遞給Global.asax檔案中定義的RegisterRoutes()方法。Global.asax檔案對應著一個名為GlobalApplication的類。

接下來,建立了一個仿製的HTTP Context,其中包含了待測試的URL。例如,在等一個測試中,URL ~/Archive/12-25-1966被傳遞到仿製的HTTP Context對象的構造器中。仿製的HTTP Context對象是我在Tip #12中建立的仿製MVC對象的修改版。本文後面可以下載到原始碼,其中的MvcFakes項目中包含了這些仿製對象。

接下來,在仿製的上下文上到用了GetRouteData()方法,並返回了路由資料。路由資料表示將URL傳遞給應用程式路由表,經過解釋後得到的結果。換句話說,路由資料是將URL與路由表中的路由進行對比後得到的結果。

最後,該測試判斷路由資料中是否包含需要的值。在第一個測試裡,驗證了控制器名字、控制器操作和Id的值。依照該測試,空的URL ~/應該映射到Home控制器、Index操作,並且Id的值是String.Empty。

第二個測試檢查了類似~/Archive/12-25-1966這樣的請求是否映射到Blog控制器、Details操作,並建立了名為entryDate的操作。

第三個測試檢查了類似~/Archive/something這樣的請求不能映射到Blog控制器。因為該URL不包含恰當的entryDate,所以不能被Blog控制器處理。

最後一個測實驗證了catchall路由能夠正確工作。該測試檢查了~/Product/a/b/c/d得到瞭解析,使得values參數等於a/b/c/d。換句話說,它檢查了catchall控制器的catch-all部分。

小結

在這個Tip中,我向你展示了一種簡單的測試自訂ASP.NET MVC路由的方法。我建議任何時候只要你修改了Global.asax檔案中的預設路由,都應該對其進行單元測試。

此處下載原始碼:http://weblogs.asp.net/blogs/stephenwalther/Downloads/Tip13/Tip13.zip。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.