[翻译] 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

默认情况下,一个路由包括名字、路径和默认路由。路由得到一个URL后会将其中的不同片段映射到特定的控制器、控制器操作和传递给操作的参数上。如:

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

URL中的第一个片段被映射到控制器名字,第二部分被映射到控制器操作,而最后一部分被映射到名字为Id的参数。

Default路由包含了默认值。如果没有指定控制器,则使用Home控制器。如果没有指定操作,则调用Index操作。如果没有指定Id,则传第一个空字符串。因此,下面的URL将被这样解释:

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

对很多MVC应用程序来说,默认路由是你经常要用到的一个。然而,你还可以选择创建自定义路由。例如,清单2中的Global.asax文件包含了两个自定义路由。

清单2 - Global.asax

清单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,请访问下面的页面:

在看过了xUnit的示例之后,我修改了仿制的上下文对象,使其能够用于对路由进行单元测试。清单3中的单元测试演示了如何对清单2中的Global.asax中包含的自定义路由进行测试。

清单3 - RouteTest.cs

这是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