Ministry of Technology
Show Menu

Testing MVC Routes with Ministry Open Source

We are once again proud to announce the release of an open source product. This time around the release is actually made up of three isolated NuGet packages which together make up the TestSupport library infrastructure. The Wiki provides more detail on the capabilities of these supporting libraries, but they are continuing to evolve with our projects.

For this article I wanted to pick up on one specific topic, MVC Routing tests.

Testing Routes in ASP.Net MVC

Ministry.TestingSupport offers a simple solution to make route testing, for both incoming and outgoing routes, really clean and simple. This is achieved through the use of two classes. The primary class is the 'MvcRouteAsserter', an instance of which is provided by the ISupportFactoryWithMocks implementation for your chosen testing framework. Moq is required for this to work at the moment but if you would like this for your chosen mocking framework feel free to join the project and add support or raise an issue and I'll add support when I can.

The MvcRouteAsserter

This is a straightforward class which simply takes an instance of IAssertionFramework and then wraps up a suite of assertions you would normally perform to test a route into one simple assertion. Assertions provided include...

  • AssertRouteIsValid
  • AssertRouteIsInvalid
  • AssertOutgoingRouteUrlGeneration

RouteTestBase

Creating a route test is very straightforward. By inheriting from TouteTestBase, you get shorthand local assertion methods that call through to the MvcRouteAsserter. There are some key things to do to set up a route test for your application, as follows...

  1. Override the 'TestSupportFactory' property with the implementation for your testing framework of choice with mocks.
  2. Override 'SetupFixture()' and ensure it's decorated to run at the beginning of the fixture or test class. It should read something like this and ensure that the Routes property is populated from the application...
[TestFixtureSetUp]
public override void SetUpFixture()
{
    Routes = new RouteCollection();
    MvcApplication app = new MvcApplication();
    app.RegisterAllRoutes(Routes);
}

Creating your own base class

It makes a lot of sense to create your own base class for route tests, inheriting from RouteTestBase. Here's my base class for the Ministry website...

[TestFixture] 
public class MinistryotechRouteTestBase : RouteTestBase
{    
#region | Setup & TearDown |    

/// <summary>
    /// Sets up the test fixture.
    /// </summary>
    [TestFixtureSetUp]
    public override void SetUpFixture()
    {
        Routes = new RouteCollection();
        MvcApplication app = new MvcApplication();
        app.RegisterAllRoutes(Routes);
    }    

#endregion    

/// <summary>
    /// Gets the test support factory.
    /// </summary>
    protected override ISupportFactory TestSupportFactory
    {
        get { return new NUnitSupportFactory(); }
    }
}

This then makes the test classes themselves really clean and readable. Here's my own NUnit tests...

[TestFixture]
public class BlogRouteTests : MinistryotechRouteTestBase
{
[Test]
[TestCase("~/blog", "index")]
[TestCase("~/blog/", "index")]
[TestCase("~/blog/page", "showpage")]
[TestCase("~/blog/page/", "showpage")]
[TestCase("~/blog/page1", "showpage")]
[TestCase("~/blog/page2/", "showpage")]
[TestCase("~/blog/page87", "showpage")]
[TestCase("~/blog/feed.rss", "feed")]
public void TestViewPageBlogRoutes(string url, string action)
{
AssertRouteIsValid(url, "list", action, "blog", HttpVerbs.Get);


[Test]
    public void TestViewPageBlogVariables()
    {
        AssertRouteIsValid("~/blog/page1", "list", "showpage", "blog", HttpVerbs.Get, new { page = 1 });
        AssertRouteIsValid("~/blog/page", "list", "showpage", "blog", HttpVerbs.Get, new { page = 1 });
        AssertRouteIsValid("~/blog/page4", "list", "showpage", "blog", HttpVerbs.Get, new { page = 4 });
    }    

[Test]
    [TestCase("/blog", "index")]
    [TestCase("/blog/page", "showpage")]
    public void TestMainBlogAreaRoutesUrlGeneration(string url, string action)
    {
        AssertOutgoingRouteUrlGeneration(url, "list", action, null, new { area = "blog" });
    }    

[Test]
    public void TestBlogAreaPagedRoutesUrlGeneration()
    {
        AssertOutgoingRouteUrlGeneration("/blog/page3", "list", "showpage", null, new { page = 3, area = "blog" });
    }    

[Test]
    public void TestInvalidViewPageBlogVariables()
    {
        // These will fall back to the hideous Umbraco catch-all
        AssertRouteIsValid("~/blog/pagedinky", "blog", "pagedinky");
        AssertRouteIsValid("~/blog/pageCabbage", "blog", "pageCabbage");
    }    

[Test]
    [TestCase("~/blog/eating-fish", "eating-fish")]
    [TestCase("~/blog/support/", "support")]
    public void TestBlogItemRoutesUseTheUmbracoRoutes(string url, string action)
    {
        AssertRouteIsValid(url, "blog", action);
    }    

[Test]
    [TestCase("~/i-dont-exist/things1/things2/things3")]
    public void TestBadRoutesDontWork(string url)
    {
        AssertRouteIsInvalid(url);
    }    

[Test]
    [TestCase("/blog/eating-fish", "eating-fish")]
    [TestCase("/blog/support", "support")]
    public void TestBlogItemRoutesUrlGeneration(string url, string action)
    {
        AssertOutgoingRouteUrlGeneration(url, "blog", action);
    }
}