5

Goal: test that a given url returns a given controller function.

In the process, I've broken into the routing system and I can't figure out how to test routes (or, for that matter, find the controller corresponding to the route :-/).

Sample code, which doesn't work:

[Test]       
public void kick_the_tires()
{
   var rc = new RouteCollection();

   Infrastructure.RouteRegistry.RegisterRoutes(rc);

   // get the route corresponding to name.
   var got = rc["name"];

   var expected = //What? foo is an internal type that can't be instantiated.

   Assert.AreEqual(foo, frob);
}

edit: Using the linked blog post from Simon for the stub class.

[TestCase("/", "~/", "Home", "Index")]
[TestCase("/", "api/command", "Other", "command")]
internal void stub_mocker(string apppath, string route, string expected_controller,\
  string expected_action)
{
  var rc = new RouteCollection();
  Infrastructure.RouteRegistry.RegisterRoutes(rc);

  var httpmock = new StubHttpContextForRouting(
      appPath: apppath,
      requestUrl: route);

  // this always returns null for everything but the Index case.
  var routeData = rc.GetRouteData(httpmock);

  var controller = routeData.Values["controller"];
  var action = routeData.Values["action"];
  Assert.AreEqual(expected_controller, controller);
  Assert.AreEqual(expected_action, action);
}

2 Answers 2

5

All you are testing right now is if the routes are added to the collection, by accessing it by the route name, and not if the expected route will return given a virtual path. You need to obtain the route data as returned by the RouteCollection with a HttpContext.

Best way would be to use a mock or a stub for the HttpContext (or HttpContextBase) and call the RouteCollection's GetRouteData(HttpContextBase) method and inspect the route data.

There is a good example of this in Brad Wilson's blog: http://bradwilson.typepad.com/blog/2010/07/testing-routing-and-url-generation-in-aspnet-mvc.html

Edit:You cannot get a controller instance from the RouteData itself. However, RouteData should give you enough information to know which controller will be instantiated. For example, if you have a controller at MyProject.Controllers.HomeController with an action Home, this should hold true in your test (using xUnit and Moq):

// Prepare
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();

context.SetupGet(c => c.Request).Returns(request.Object);
context.SetupGet(c => c.Response).Returns(response.Object);
context.SetupGet(c => c.Session).Returns(session.Object);
context.SetupGet(c => c.Server).Returns(server.Object);
request.SetupGet(r => r.HttpMethod).Returns("GET");
request.SetupGet(r => r.PathInfo).Returns(String.Empty);
request.SetupGet(r => r.AppRelativeCurrentExecutionFilePath).Returns("~/Home");


var expectedHandler = typeof (HomeController).GetMethod("Index", Type.EmptyTypes);

var data = RouteTable.Routes.GetRouteData(context.Object);

Assert.NotNull(data);

var handler = (MethodInfo) data.DataTokens["actionMethod"];
Assert.Equal(expectedHandler, handler);
Sign up to request clarification or add additional context in comments.

14 Comments

Thanks, Simon (Welcome to StackOverflow!). Can you comment on how to get a controller back from a route, as that's what I'm really trying to do?
Simon, this isn't working. I don't totally grasp the MVC4 world, but I believe DataToken is supposed to contain the params from the route, not the methods being triggered.
Followup: RouteData.Route.DataTokens doesn't exist; Routedata.DataTokens does.
I edited my example to provide an example of mocking the HttpContext, and fixed the redundancy for the DataTokens dictionary. The code passes my unit test (with a different controller). DataTokens will contain any extra properties that are passed to route handlers. The constraints, namespaces, etc.. are contained in the Values dictionary. msdn.microsoft.com/en-us/library/…
Simon, GetRouteData keeps returning null for non-index lookups. I've hacked around it for a while and have been looking at purported source. Any ideas?
|
1

I've had prety good experience with MVCContrib's Testhelper

Take a look at this test of testhelper.

Saves a lot of hassles around stubbing HttpContext etc.

Also if you are on MVC4, have a look at this Nuget package which is a fork for MVC4.

1 Comment

I agree with you, testing anything that requires HttpContext is painful enough that a library that does the work for you is always useful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.