• How to easily unit test MVC routes using Fakes

    Published by on March 15th, 2013 12:07 pm under c#, Fakes, MVC, unit testing

    No Comments

    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:

    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;
    }
    

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

    // Act
    HttpContextBase context;
    using (this.MocksForMVCRouteTesting("{mvc_route_to_text_here}", out context))
    {
      var routeData = routes.GetRouteData(context);
    
      // Asserts here...
    }
    

    And what about a real like example?

      // 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()));
      }
    

    Hope that you can find this useful :).

    Tags: , , , ,