How to easily unit test MVC routes using Fakes

In this short post I will show you how you can easily test your MVC routes using Fakes as mocking framework. Besides there is a lot of mocking frameworks you can choose to unit test your code, Fakes provides you the ability to mock almost any class within the framework, not just interfaces or virtual things.

The following concepts are first class citizens within the Fakes ecosystem:

  • stub replaces another class with a small substitute that implements the same interface. To use stubs, you have to design your application so that each component depends only on interfaces, and not on other components.
  • shim modifies the compiled code of your application at run time so that instead of making a specified method call, it runs the shim code that your test provides. Shims can be used to replace calls to assemblies that you cannot modify, such .NET assemblies.

Basically stubs are what you find in many other mocking frameworks for .NET, but shims provides extra value by allowing you to modify the compiled code (not targeting the classes you want to test, but the classes those ones rely on). You can read more about Fakes and usage here.

Here I’ll show you how you can mock base classes within the ASP.NET pipeline as HttpContextBase, HttpRequestBase and HttpResponseBase in order to set up everything MVC needs to resolve a route.

So you can add a private method to your fixture setting up these mocks like the following one:

[sourcecode language=”csharp”]
private IDisposable MocksForMVCRouteTesting(string requestUrl, out HttpContextBase contextBase)
{
var shimsContext = ShimsContext.Create();
var requestBase = new System.Web.Fakes.StubHttpRequestBase
{
ApplicationPathGet = () => "/",
AppRelativeCurrentExecutionFilePathGet = () => requestUrl
};

contextBase = new System.Web.Fakes.StubHttpContextBase
{
RequestGet = () => requestBase,
ResponseGet = () => new System.Web.Fakes.StubHttpResponseBase()
};

return shimsContext;
}
[/sourcecode]

Ok, now you got your mocks to test the routes, but how to use it? Easy, following the next pattern:

[sourcecode language=”csharp”]
// Act
HttpContextBase context;
using (this.MocksForMVCRouteTesting("{mvc_route_to_text_here}", out context))
{
var routeData = routes.GetRouteData(context);

// Asserts here…
}
[/sourcecode]

And what about a real like example?

[sourcecode language=”csharp”]
// Arrange
var routes = new RouteCollection();
RouteConfig.RegisterRoutes(routes);

// Act
HttpContextBase context;
using (this.MocksForMVCRouteTesting("~/account/register/", out context))
{
var routeData = routes.GetRouteData(context);

// Assert
Assert.IsNotNull(routeData);
Assert.AreEqual("Account", (string)routeData.Values["controller"], true);
Assert.AreEqual("Register", (string)routeData.Values["action"], true);
Assert.IsTrue(string.IsNullOrWhiteSpace(routeData.Values["id"].ToString()));
}
[/sourcecode]

Hope that you can find this useful :).



Leave a Reply