# Saturday, 12 December 2009
« Adding cut and paste character count fun... | Main | The reappearing calendar. A gotcha to av... »

Testing the routes in .Net MVC can be a bit tedious without some help.  MVCContrib’s TestHelper library eases the load and makes testing routes a breeze.

To demonstrate, I created an application to manage recipes with their ingredients and directions. Below is how I wanted the routing to work.

What I want the URL to look like What it will do
/recipe List all recipes
/recipe/blueberrypie Display blueberry pie recipe
/recipe/edit/blueberrypie Edit blueberry pie recipe
/recipe/blueberrypie/ingredients Show the ingredients for blueberry pie
/recipe/blueberrypie/directions Show directions for blueberry pie
/recipe/blueberrypie/ingredients/delete/1234 Delete ingredient with ID 1234 for blueberry pie & go back to the list of ingredients

I edited the RegisterRoutes method in the Global.asax.cs file to match the table:

// recipe/BlueberryPie/ingredients/edit/1234
routes.MapRoute(
    "Ingredients",
    "recipe/{nameKey}/ingredients/{action}/{id}",
    new { controller = "Ingredients", action = "Index" },
    new { id = @"\d+" }
    );

// recipe/BlueberryPie/ingredients/
routes.MapRoute(
    "IngredientsForRecipe",
    "recipe/{nameKey}/ingredients/{action}",
    new { controller = "Ingredients", action = "List" }
    );

// recipe/BlueberryPie/directions/edit/1234
routes.MapRoute(
    "Directions",
    "recipe/{nameKey}/directions/{action}/{id}",
    new { controller = "directions", action = "Index" },
    new { id = @"\d+" }
    );

// recipe/BlueberryPie/directions/
routes.MapRoute(
    "DirectionsForRecipe",
    "recipe/{nameKey}/directions/{action}",
    new { controller = "directions", action = "List" }
    );

// recipe/edit/BlueberryPie
routes.MapRoute(
    null,
    "recipe/{action}/{nameKey}",
    new { controller = "Recipe", action = "List", nameKey = "" },
    new { action = "create|edit|index|list" }
    );

// recipe/BlueberryPie
routes.MapRoute(
    "recipe",
    "recipe/{nameKey}",
     new { controller = "Recipe", action = "Index" }
    );

Now for the magic with MVCContrib’s TestHelper library and the extension ShouldMapTo:

[TestFixture]
public class RouteTests
{
    [TestFixtureSetUp]
    public void SetUp()
    {
        RouteTable.Routes.Clear();
        MvcApplication.RegisterRoutes(RouteTable.Routes); 
    }

    [Test]
    public void RootMatchesHome()
    {
        "~/".ShouldMapTo(x => x.Index());
    }

    [Test]
    public void RecipeRootMatchesList()
    {
        "~/recipe".ShouldMapTo(x => x.List());
    }

    [Test]
    public void RecipeNameShouldDisplayIndex()
    {
        "~/recipe/BlueberryPie".ShouldMapTo(x => x.Index("BlueberryPie")); 
    }

    [Test]
    public void CreateRecipeShouldDisplayCreateAction()
    {
        "~/recipe/create/".ShouldMapTo(x => x.Create());
    }

    [Test]
    public void EditRecipeShouldDisplayEditAction()
    {
        "~/recipe/edit/BlueberryPie".ShouldMapTo(x => x.Edit("BlueberryPie"));
    }
    [Test]
    public void DeleteRecipeShouldDisplayDeleteAction()
    {
        "~/recipe/delete/1".ShouldMapTo(x => x.Delete(1));
    }
    [Test]
    public void IngredientsForRecipeShouldDisplayIngredientsListAction()
    {
        "~/recipe/BlueberryPie/ingredients".ShouldMapTo(i => i.List("BlueberryPie")); 
    }
    [Test]
    public void DirectionsForRecipeShouldDisplayIngredientsListAction()
    {
        "~/recipe/BlueberryPie/directions".ShouldMapTo(i => i.List("BlueberryPie"));
    }
    [Test]
    public void DeleteIngredientShouldDisplayDeleteAction()
    {
        "~/recipe/BlueberryPie/ingredients/delete/1".ShouldMapTo(i => i.Delete(1));
    }
    [Test]
    public void DeleteDirectionShouldDisplayDeleteAction()
    {
        "~/recipe/BlueberryPie/directions/delete/1".ShouldMapTo(i => i.Delete(1));
    }
}

No need to mock/fake any context, setup route data, etc.  The code is short and sweet, easy to read, understand and matches the URL that would be in the browser making it very intuitive.

Please download the code.  The sample is using NUnit 2.5.

MVCContribTestRoutes.zip (603.49 KB)

Happy coding!

Posted 12.12.2009  #    Comments [0]  |