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!