Asp.Net MvC 3 from scratch: Routing

This is the second article in the series where we create a book review application from scratch using Asp.Net MvC 3. In the first article i did a general introduction and created the project. In this article we are going to discuss the importance of automated testing and were going to finally going to write some code for testing our routes.

The routing mechanism is vital to the mapping of requests within our application. This makes subjecting routes to automated testing a valid investment of time. Automated testing of routes requires the help of a mocking framework, there a several frameworks available, i will be using MOQ for this article series.

We will be installing MOQ with help of the NuGet package manager. The easiest way to install third party libraries using NuGet is simply through the GUI. Click references insight the unit-test project and click “Add package reference”. In the next screen select “All” under the “Online” section on the left, then enter your search in the upper right corner like shown in the screenshot below. MOQ is the fourth result in de search results, click it and then click install.

This is just a simple example of the power of NuGet, installing complex libraries with dependencies is just as easy. You can use the same approach to update your third party libraries by selecting “All” under the “Updates” section on the left, so there is no more manual importing of any libraries anymore, hurray!

Unit-testing

We will be writing tests during the development of our application. Now that we got MOQ installed, lets talk about the importance of automated testing in the form of unit-testing. If you have limited or no experience with automated testing or unit-testing, it is recommended to read up on the subject, at least the basics before continuing. check out my resource page for recommended reading.

Before we get to why we should unit-test, lets set a definition for unit-testing. The clearest definition i have come across is one made by Roy Osherove: A unit-test is a an automated piece of code that invokes the method or class being tested and then checks some assumptions about the logical behavior of that method or class. A unit-test is always always written using a unit-testing framework. It is fully automated, trustworthy, readable and maintainable.

But why should we as developers be bothered with unit-testing the first place? Well basically because we should care about the quality of our the web applications we develop. Delivering quality can be a challenge with a constantly evolving application, unit-testing provides a means to enhance and maintain the quality of our web application. The three major advantages offered by unit-testing are:

  • Unit-testing allows for easy refactoring. Readily-available unit tests make it easy for the programmer to check whether a piece of code is still working properly after a change. If a change causes a fault, it can be quickly identified and fixed.
  • Unit-testing makes for great technical documentation. Developers somehow need to convey the functionally offered by class or method to other developers. One of the possibilities is looking at the unit-tests to gain a basic understanding off a class or method.
  • Unit-testing promotes good coding. An important aspect of good coding is loose coupling. Loose coupling is a prerequisite for testing code with dependencies because it enables the replacements of dependencies with test doubles (stubs, mocks). This is the only way to control how dependencies will behave when under test, which is vital for unit-testing.

Having discussed the advantages of unit-testing, it’s only fair to point out that that unit-testing is not able to cover all the bases, unit-testing has it’s limitations and you should not reply soulfully on one technique. The first limitation of unit-testing is that it does not cover integration between different parts of the system. The second limitation is that the test scenarios are created by the developer. Somehow end-users tend to be creative and use/abuse the application in ways that developers do not expect and therefore are not covered by unit-testing.

While unit-testing does not cover all the bases, it is very important for the overall quality of the application. Just do not soulfully on unit-testing, some form of integration testing and user testing are important to prepare an application for “the real world”. Now let’s do some unit-testing of our own.

Routing

As mentioned before, we will start with the automated testing of our routes! The routing mechanism is vital to the mapping of requests within our application. This makes subjecting routes to automated testing a valid investment of time.

The challenge with testing routes is that the routing mechanism expects an request from the user, in the form of an HttpContext instance. This is a dependency, which we are going to replace with a special test double called a mock using the MOQ framework. We configure the mock to behave the way we want, faking a request from the user and giving us control over the dependency behaves.

With the mock in place, we call the routing mechanism, passing in our mocked object. The routing mechanism then returns a the route data, which contains the information on how the routing mechanism will map the request. We can check the contents of the route data to see how the request would be mapped.  Now let’s see the code:

using System.Web;
using System.Web.Routing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace BookReviews.Web.Tests.Routes
{
    public static class RouteTestHelpers
    {
        public static Mock<HttpContextBase> BuildMockHttpContext(string url)
        {
            // Create a mock instance of the HttpContext class.
            var mockHttpContext = new Mock<HttpContextBase>();

            // Decorate our mock object with the desired behaviour.
            var mockRequest = new Mock<HttpRequestBase>();
            mockHttpContext.Setup(x => x.Request).Returns(mockRequest.Object);
            mockRequest.Setup(x => x.AppRelativeCurrentExecutionFilePath).Returns(url);

            var mockResponse = new Mock<HttpResponseBase>();
            mockHttpContext.Setup(x => x.Response).Returns(mockResponse.Object);
            mockResponse.Setup(x => x.ApplyAppPathModifier(It.IsAny<string>())).Returns<string>(x => x);

            return mockHttpContext;
        }

        public static RouteData GetRouteDataForMockedRequest(string url)
        {
            var routes = new RouteCollection();
            MvcApplication.RegisterRoutes(routes);

            // Create a mock instance of the HttpContext class with the desired behaviour.
            var mockHttpContext = BuildMockHttpContext(url);

            return routes.GetRouteData(mockHttpContext.Object);
        }
    }

    [TestClass]
    public class RouteTests
    {
        [TestMethod]
        public void TestReviewControllerIndexRoute()
        {
            RouteData routeData = RouteTestHelpers.GetRouteDataForMockedRequest("~/review/index");

            // Check if the route was mapped as expected.
            Assert.IsTrue(routeData != null && routeData.Values["controller"].ToString() == "review");
            Assert.IsTrue(routeData != null && routeData.Values["action"].ToString() == "index");
        }
    }
}

The code should be pretty straightforward with the commenting provided and the explanation provided earlier. As you may have noticed pretty much all of the code is reusable, so adding tests for new routes takes very little effort. In the next article we will start coding a lot more with our model. So this is it for the second article! Feel free to ask questions, feedback is much appreciated. Get the full source code for our progress so far from here!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>