... but the same extension method works when the application itself is executing. The UrlHelper extension method itself looks like this:
public static string CategoryLandingPage(this UrlHelper helper, string seoCategoryName)
{
return helper.RouteUrl("Category", new { area = "SoAndSo", controller = "SoAndSo", action = "Category", seoCategoryName = seoCategoryName }, "http");
}
I register that particular route like this in my SoAndSoAreaRegistration class:
context.MapRoute(
"Category",
"category/{seoCategoryName}",
new { area = "SoAndSo", controller = "SoAndSo", action = "Category", seoCategoryName = string.Empty }
);
... and I have dropped a breakpoint on that registration to ensure that it gets hit by the test runner, and it does.
When I run the test, I get an ArgumentException, "A route named 'Category' could not be found in the route collection. Parameter name: name".
My guess is that we do not need to specify the route name and enough route parameters (area/controller/action/category name) to construct the route in its entirety as we're doing here, but I can't figure out where the route name disappears to during testing. Removing the category name eliminates the exception and allows the test to pass, but I would still like to understand where the route name disappears to when I'm testing. Simplifying the code like so still blows up at runtime:
public static string CategoryLandingPage(this UrlHelper helper, string seoCategoryName)
{
return helper.RouteUrl("Category");
}
If I dig through the route collection at runtime, I can find the category route, but there is no evidence of a .Name property, nor do I see the route's name ("Category" with a capital C) anywhere among the UrlHelper's properties (apologies for the goofy obfuscation; better safe than sorry):
Does anyone know how I can write unit tests which hit UrlHelper extension methods which reference routes by their name? Thanks!
Update - I'll add some of the test initialization, most of which I got from this popular question, lightly modified to account for the fact that the application I'm working with is separated into multiple MVC areas:
private SoAndSoController CreateController() { var service = new Mock(); var cookieMgr = new Mock(); var logger = new Mock();
var allRoutes = new RouteCollection(); MvcApplication.RegisterRoutes(allRoutes); var soAndSoAreaRegistration = new SoAndSoAreaRegistration(); var soAndSoAreaRegistrationContext = new AreaRegistrationContext(soAndSoAreaRegistration.AreaName, new RouteCollection()); soAndSoAreaRegistration.RegisterArea(soAndSoAreaRegistrationContext); soAndSoAreaRegistrationContext.Routes.ForEach(r => allRoutes.Add(r)); var request = new Mock<HttpRequestBase>(); request.SetupGet(x => x.ApplicationPath).Returns("/"); request.SetupGet(x => x.Url).Returns(new Uri("http://localhost/a", UriKind.Absolute)); request.SetupGet(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection()); var response = new Mock<HttpResponseBase>(); response.Setup(x => x.ApplyAppPathModifier("/post1")).Returns("http://localhost/post1"); var context = new Mock<HttpContextBase>(); context.SetupGet(x => x.Request).Returns(request.Object); context.SetupGet(x => x.Response).Returns(response.Object); var controller = new SoAndSoController(service.Object, cookieMgr.Object, null, logger.Object, null); controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller); controller.Url = new UrlHelper(new RequestContext(context.Object, new RouteData()), allRoutes); return controller;
}