.net – Unit testing ASP.NET MVC 2 routes with areas bails out on AreaRegistration.RegisterAllAreas()

asp.net-mvc-2mstestnetunit testingvisual studio 2010

I'm unit testing my routes in ASP.NET MVC 2. I'm using MSTest and I'm using areas as well.

[TestClass]
public class RouteRegistrarTests
{
    [ClassInitialize]
    public static void ClassInitialize(TestContext testContext)
    {
        RouteTable.Routes.Clear();

        RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        RouteTable.Routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });

        AreaRegistration.RegisterAllAreas();

        routes.MapRoute(
            "default",
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }

    [TestMethod]
    public void RouteMaps_VerifyMappings_Match()
    {
        "~/".Route().ShouldMapTo<HomeController>(n => n.Index());
    }
}

When it executes AreaRegistration.RegisterAllAreas() however, it throws this exception:

System.InvalidOperationException: System.InvalidOperationException: This method cannot be called during the application's pre-start initialization stage.

So, I reckon I can't call it from my class initializer. But when can I call it? I obviously don't have an Application_Start in my test.

Best Answer

I solved this by creating an instance of my AreaRegistration class and calling the RegisterArea method.

For example, given an Area named "Catalog" with this route:

public override void RegisterArea(AreaRegistrationContext context)
{
  context.MapRoute(
      "Catalog_default",
      "Catalog/{controller}/{action}/{id}",
      new {controller = "List", action = "Index", id = "" }
  );
}

This is my test method:

[TestMethod]
public void TestCatalogAreaRoute()
{
  var routes = new RouteCollection();

  // Get my AreaRegistration class
  var areaRegistration = new CatalogAreaRegistration();
  Assert.AreEqual("Catalog", areaRegistration.AreaName);

  // Get an AreaRegistrationContext for my class. Give it an empty RouteCollection
  var areaRegistrationContext = new AreaRegistrationContext(areaRegistration.AreaName, routes);
  areaRegistration.RegisterArea(areaRegistrationContext);

  // Mock up an HttpContext object with my test path (using Moq)
  var context = new Mock<HttpContextBase>();
  context.Setup(c => c.Request.AppRelativeCurrentExecutionFilePath).Returns("~/Catalog");

  // Get the RouteData based on the HttpContext
  var routeData = routes.GetRouteData(context.Object);

  Assert.IsNotNull(routeData, "Should have found the route");
  Assert.AreEqual("Catalog", routeData.DataTokens["area"]);
  Assert.AreEqual("List", routeData.Values["controller"]);
  Assert.AreEqual("Index", routeData.Values["action"]);
  Assert.AreEqual("", routeData.Values["id"]);
}
Related Topic