July 2012

Volume 27 Number 07

ASP.NET MVC 4 - Test-Driving ASP.NET MVC

By Keith Burnell | July 2012

At the core of the Model-View-Controller (MVC) pattern is the segregation of UI functions into three components. The model represents the data and behavior of your domain. The view manages the display of the model and handles interactions with users. The controller orchestrates the interactions between the view and the model. This separation of inherently difficult-to-test UI logic from the business logic makes applications implemented with the MVC pattern extremely testable. In this article I’ll discuss best practices and techniques for enhancing the testability of your ASP.NET MVC applications, including how to structure your solution, architecting your code to handle the injection of dependencies and implementing dependency injection with StructureMap.

Structuring Your Solution for Maximum Testability

What better way to start our discussion than where every developer starts a new project: creating the solution. I’ll discuss some best practices for laying out your Visual Studio solution based on my experience developing large enterprise ASP.NET MVC applications using test-driven development (TDD). To start, I suggest using the empty project template when creating an ASP.NET MVC project. The other templates are great for experimenting or creating proofs of concept, but they generally contain a lot of noise that’s distracting and unnecessary in a real enterprise application.

Whenever you create any type of complex application, you should use an n-tier approach. For ASP.NET MVC application development, I recommend using the approach illustrated in Figure 1 and Figure 2, which contain the following projects:

  • The Web project contains all the UI-specific code, including views, view models, scripts, CSS and so forth. This layer has the ability to access only the Controllers, Service, Domain and Shared projects.
  • The Controllers project contains the controller classes used by ASP.NET MVC. This layer communicates with the Service, Domain and Shared projects.
  • The Service project contains the application’s business logic. This layer communicates with the DataAccess, Domain and Shared projects.
  • The DataAccess project contains the code used to retrieve and manipulate the data that drives the application. This layer communicates with the Domain and Shared projects.
  • The Domain project contains the domain objects used by the application and is prohibited from communicating with any of the projects.
  • The Shared project contains code that needs be available to multiple other layers, such as loggers, constants and other common utility code. It’s allowed to communicate only with the Domain project.

Interaction Among Layers
Figure 1 Interaction Among Layers

Example Solution Structure
Figure 2 Example Solution Structure

I recommend placing your controllers into a separate Visual Studio project. For information on how this is easily accomplished, see the post at bit.ly/K4mF2B. Placing your controllers in a separate project lets you further decouple the logic that resides in the controllers from the UI code. The result is that your Web project contains only code that’s truly related to the UI.

Where to Put Your Test Projects Where you locate your test projects and how you name them is important. When you’re developing complex, enterprise-level applications, the solutions tend to get pretty large, which can make it difficult to locate a specific class or piece of code in Solution Explorer. Adding multiple test projects to your existing code base only adds to the complexity of navigation in Solution Explorer. I highly recommend physically separating your test projects from your actual application code. I suggest placing all test projects in a Tests folder at the solution level. Locating all your test projects and tests in a single solution folder significantly reduces the noise in your default Solution Explorer view and allows you to easily locate your tests.

Next you’ll want to separate the types of tests. More than likely, your solution will contain a variety of test types (unit, integration, performance, UI and so on), and it’s important to isolate and group each test type. Not only does this make it easier to locate specific test types, but it also lets you easily run all tests of a specific type. If you’re using either of the most popular Visual Studio productivity tool suites, ReSharper (jetbrains.com/ReSharper) or CodeRush (devexpress.com/CodeRush), you get a context menu that allows you to right-click any folder, project or class in Solution Explorer and run all tests contained in the item. To group tests by test type, create a folder for each type of test you plan to write inside the Tests solution folder.

Figure 3 shows an example Tests solution folder containing a number of test type folders.

An Example Tests Solution Folder
Figure 3 An Example Tests Solution Folder

Naming Your Test Projects How you name your test projects is as important as where you locate them. You want to be able to easily distinguish what part of your application is under test in each test project and what type of tests the project contains. For this, it’s a good idea to name your test projects using the following convention: [Full Name of Project Under Test].Test.[Test Type]. This allows you to, at a glance, determine exactly what layer of your project is under test and what type of test is being performed. You may be thinking that putting the test projects in type-specific folders and including the test type in the name of the test project is redundant, but remember that solution folders are used only in Solution Explorer and are not included in the namespaces of the projects files. So although the Controllers unit test project is in the Tests\Unit solution folder, the namespace—TestDrivingMVC.Controllers.Test.Unit—doesn’t reflect that folder structure. Adding the test type when naming the project is necessary to avoid naming collisions and to determine what type of test you’re working within the editor. Figure 4 shows Solution Explorer with test projects.

Test Projects in Solution Explorer
Figure 4 Test Projects in Solution Explorer

Introducing Dependency Injection to Your Architecture

You can’t get very far unit testing an n-tier application before you encounter a dependency in your code under test. These dependencies could be other layers of your application, or they could be completely external to your code (such as a database, file system or Web services). When you’re writing unit tests, you need to deal with this situation correctly and use test doubles (mocks, fakes or stubs) when you encounter an external dependency. For more information on test doubles, refer to “Exploring the Continuum of Test Doubles” (msdn.microsoft.com/magazine/cc163358) in the September 2007 issue of MSDN Magazine. Before you can take advantage of the flexibility that test doubles offer, however, your code has to be architected to handle the injection of dependencies.

Dependency Injection Dependency injection is the process of injecting the concrete implementations a class requires rather than the class directly instantiating the dependency. The consuming class is not aware of an actual concrete implementation of any of its dependencies, but knows only of the interfaces that back the dependencies; the concrete implementations are provided either by the consuming class or by a dependency injection framework.

The goal of dependency injection is to create extremely loosely coupled code. The loose coupling lets you easily substitute test double implementations of your dependencies when writing unit tests.

There are three primary ways to accomplish dependency injection:

  • Property injection
  • Constructor injection
  • Using a dependency injection framework/Inversion of Control container (referred to from this point as a DI/IoC framework)

With property injection, you expose public properties on your object to enable its dependencies to be set, as shown in Figure 5. This approach is straightforward and requires no tooling.

Figure 5 Property Injection

// Employee Service
public class EmployeeService : IEmployeeService {
  private ILoggingService _loggingService;
  public EmployeeService() {}
  public ILoggingService LoggingService { get; set; }
  public decimal CalculateSalary(long employeeId) {
    EnsureDependenciesSatisfied();
    _loggingService.LogDebug(string.Format(
      "Calculating Salary For Employee: {0}", employeeId));
    decimal output = 0;
    /*
    * Complex logic that needs to be performed
    * in order to determine the employee's salary
    */
    return output;
  }
  private void EnsureDependenciesSatisfied() {
    if (_loggingService == null)
      throw new InvalidOperationException(
        "Logging Service dependency must be satisfied!");
    }
  }
}
// Employee Controller (Consumer of Employee Service)
public class EmployeeController : Controller {
  public ActionResult DisplaySalary(long id) {
    EmployeeService employeeService = new EmployeeService();
    employeeService.LoggingService = new LoggingService();
    decimal salary = employeeService.CalculateSalary(id);
    return View(salary);
  }
}

There are three downsides to this approach. First, it puts the consumer in charge of supplying the dependencies. Next, it requires you to implement guarding code in your objects to ensure the dependencies are set before being used. Finally, as the number of dependencies your object has increases, the amount of code required to instantiate the object increases as well.

Implementing dependency injection using constructor injection involves supplying dependencies to a class via its constructor when the constructor is instantiated, as shown in Figure 6. This approach is also straightforward but, unlike property injection, you are assured that the class’s dependencies are always set.

Figure 6 Constructor Injection

// Employee Service
public class EmployeeService : IEmployeeService {
  private ILoggingService _loggingService;
  public EmployeeService(ILoggingService loggingService) {
    _loggingService = loggingService;
  }
  public decimal CalculateSalary(long employeeId) {
    _loggingService.LogDebug(string.Format(
      "Calculating Salary For Employee: {0}", employeeId));
    decimal output = 0;
    /*
    * Complex logic that needs to be performed
    * in order to determine the employee's salary
    */
    return output;
  }
}
// Consumer of Employee Service
public class EmployeeController : Controller {
  public ActionResult DisplaySalary(long employeeId) {
    EmployeeService employeeService =
      new EmployeeService(new LoggingService());
    decimal salary = employeeService.CalculateSalary(employeeId);
    return View(salary);
  }
}

Unfortunately, this approach still requires the consumer to supply the dependencies. Moreover, it’s really suitable only for small applications. Larger applications generally have too many dependencies to supply them via the object’s constructor.

The third way to implement dependency injection is to use a DI/IoC framework. A DI/IoC framework completely removes the responsibility of supplying dependencies from the consumer and lets you configure your dependencies at design time and have them resolved at run time. There are many DI/IoC frameworks available for .NET, including Unity (Microsoft’s offering), StructureMap, Castle Windsor, Ninject and more. The concept underlying all the different DI/IoC frameworks is the same, and choosing one typically comes down personal preference. To demonstrate DI/IoC frameworks in this article, I’ll use StructureMap.

Taking Dependency Injection to the Next Level with StructureMap

StructureMap (structuremap.net) is a widely adopted dependency-injection framework. You can install it via NuGet with either the Package Manager Console (Install-Package StructureMap) or with the NuGet Package Manager GUI (right-click your project’s references folder and select Manage NuGet Packages).

Configuring Dependencies with StructureMap The first step in implementing StructureMap in ASP.NET MVC is to configure your dependencies so StructureMap knows how to resolve them. You do this in the Application_Start method of the Global.asax in either of two ways.

The first way is to manually tell StructureMap that for a specific abstract implementation it should use a specific concrete implementation:

ObjectFactory.Initialize(register => {
  register.For<ILoggingService>().Use<LoggingService>();
  register.For<IEmployeeService>().Use<EmployeeService>();
});

A drawback of this approach is that you have to manually register each of the dependencies in your application, and with large applications this could become tedious. Moreover, because you register your dependencies in the Application_Start of your ASP.NET MVC site, your Web layer must have direct knowledge of every other layer of your application that has dependencies to wire up.

You can also use the StructureMap auto registration and scanning features to inspect your assemblies and wire up dependencies automatically. With this approach, StructureMap scans your assemblies, and when it encounters an interface it looks for an associated concrete implementation (based on the notion that an interface named IFoo would by convention map to the concrete implementation Foo):

ObjectFactory.Initialize(registry => registry.Scan(x => {
  x.AssembliesFromApplicationBaseDirectory();
  x.WithDefaultConventions();
}));

StructureMap Dependency Resolver Once you have your dependencies configured, you need to be able to access them from your code base. This is accomplished by creating a dependency resolver and locating it in the Shared project (because it will need to be accessed by all layers of the application that have dependencies): 

public static class Resolver {
  public static T GetConcreteInstanceOf<T>() {
    return ObjectFactory.GetInstance<T>();
  }
}

The Resolver class (as I like to call it, because Microsoft introduced a DependencyResolver class with ASP.NET MVC 3, which I’ll discuss in a bit) is a simple static class that contains one function. The function accepts a generic parameter T that represents the interface for which you’re seeking a concrete implementation, and returns T, which is the actual implementation of the passed-in interface.

Before I jump into how to use the new Resolver class in your code, I want to address why I wrote my own homegrown dependency resolver instead of creating a class that implements the IDependencyResolver interface introduced with ASP.NET MVC 3. The inclusion of the IDependencyResolver functionality is an awesome addition to ASP.NET MVC and a great stride in promoting proper software practices. Unfortunately, it resides in the System.Web.MVC DLL, and I don’t want to have references to a Web-technology-specific library in the non-Web layers of my application architecture.

Resolving Dependencies in Code Now that all the hard work is done, resolving dependencies in your code is simple. All you need to do is call the static GetConcreteInstanceOf function of the Resolver class and pass it the interface for which you’re seeking a concrete implementation, as shown in Figure 7.

Figure 7 Resolving Dependencies in Code

public class EmployeeService : IEmployeeService {
  private ILoggingService _loggingService;
  public EmployeeService() {
    _loggingService = 
      Resolver.GetConcreteInstanceOf<ILoggingService>();
  }
  public decimal CalculateSalary(long employeeId) {
    _loggingService.LogDebug(string.Format(
      "Calculating Salary For Employee: {0}", employeeId));
    decimal output = 0;
    /*
    * Complex logic that needs to be performed
    * in order to determine the employee's salary
    */
    return output;
  }
}

Taking Advantage of StructureMap to Inject Test Doubles in Unit Tests Now that the code is architected so you can inject dependencies without any intervention from the consumer, let’s get back to the original task of correctly dealing with dependencies in unit tests. Here’s the scenario:

  • The task is to write logic using TDD that generates the salary value to return from the CalculateSalary method of the EmployeeService. (You’ll find the EmployeeService and CalculateSalary functions in Figure 7.)
  • There’s a requirement that all calls to the CalculateSalary function must be logged.
  • The interface for the logging service is defined, but the implementation is not complete. Calling the logging service currently throws an exception.
  • The task needs to be completed before work on the logging service is scheduled to start.

It’s more than likely you’ve encountered this type of scenario before. Now, however, you have the proper architecture in place to be able to sever the tie to the dependency by putting a test double in its place. I like to create my test doubles in a project that can be shared among all of my test projects. As you can see in Figure 8, I’ve created a Shared project in my Tests solution folder. Inside the project I added a Fakes folder because, to complete my testing, I need a fake implementation of the ILoggingService.

Project for Shared Test Code and Fakes
Figure 8 Project for Shared Test Code and Fakes

Creating a fake for the logging service is easy. First, I create a class inside my Fakes folder named LoggingServiceFake. LoggingServiceFake needs to satisfy the contract that the EmployeeService is expecting, which means it needs to implement ILoggingService and its methods. By definition, a fake is a stand-in that contains just enough code to satisfy the interface. Typically, this means it has empty implementations of void methods and the function implementations contain a return statement that returns a hardcoded value, like so:

public class LoggingServiceFake : ILoggingService {
  public void LogError(string message, Exception ex) {}
  public void LogDebug(string message) {}
  public bool IsOnline() {
    return true;
  }
}

Now that the fake is implemented, I can write my test. To start out, I’ll create a test class in the TestDrivingMVC.Service.Test.Unit unit test project and, per the naming conventions discussed earlier, I’ll name it EmployeeServiceTest, as shown in Figure 9.

Figure 9 The EmployeeServiceTest Test Class

[TestClass]
public class EmployeeServiceTest {
  private ILoggingService _loggingServiceFake;
  private IEmployeeService _employeeService;
  [TestInitialize]
  public void TestSetup() {
    _loggingServiceFake = new LoggingServiceFake();
    ObjectFactory.Initialize(x => 
      x.For<ILoggingService>().Use(_loggingServiceFake));
    _employeeService = new EmployeeService();
  }
  [TestMethod]
  public void CalculateSalary_ShouldReturn_Decimal() {
    // Arrange
    long employeeId = 12345;
    // Act
    var result = 
      _employeeService.CalculateSalary(employeeId);
    // Assert
    result.ShouldBeType<decimal>();
  }
}

For the most part, the test class code is straightforward. The line you want to pay particularly close attention to is:

ObjectFactory.Initialize(x =>
    x.For<ILoggingService>().Use(
    _loggingService));

This is the code that instructs StructureMap to use the LoggingServiceFake when the Resolver class we created earlier attempts to resolve ILoggingService. I put this code in a method marked with TestInitialize, which tells the unit-testing framework to execute this method prior to running every test in the test class.

Using the power of DI/IoC and the StructureMap tool, I’m able to completely sever the tie to the Logging Service. Doing this enables me to complete my coding and unit testing without being affected by the state of the logging service, and to code true unit tests that don’t rely on any dependencies.

Using StructureMap as the Default Controller Factory ASP.NET MVC provides an extensibility point that lets you add a custom implementation of how controllers are instantiated in your application. By creating a class that inherits from DefaultControllerFactory (see Figure 10), you can control how controllers are created.

Figure 10 Custom Controller Factory

public class ControllerFactory : DefaultControllerFactory {
  private const string ControllerNotFound = 
  "The controller for path '{0}' could not be found or it does not implement IController.";
  private const string NotAController = "Type requested is not a controller: {0}";
  private const string UnableToResolveController = 
    "Unable to resolve controller: {0}";
  public ControllerFactory() {
    Container = ObjectFactory.Container;
  }
  public IContainer Container { get; set; }
  protected override IController GetControllerInstance(
    RequestContext context, Type controllerType) {
    IController controller;
    if (controllerType == null)
      throw new HttpException(404, String.Format(ControllerNotFound,
      context.HttpContext.Request.Path));
    if (!typeof (IController).IsAssignableFrom(controllerType))
      throw new ArgumentException(string.Format(NotAController,
      controllerType.Name), "controllerType");
    try {
      controller = Container.GetInstance(controllerType) 
        as IController;
    }
    catch (Exception ex) {
      throw new InvalidOperationException(
      String.Format(UnableToResolveController, 
        controllerType.Name), ex);
    }
    return controller;
  }
}

In the new controller factory, I have a public StructureMap Container property that gets set based on the StructureMap ObjectFactory (which is configured in Figure 10 in the Global.asax).

Next, I have an override of the GetControllerInstance method that does some type checking and then uses the StructureMap container to resolve the current controller based on the supplied controller type parameter. Because I used the StructureMap auto registration and scanning features when configuring StructureMap initially, there’s nothing else I have to do.

The benefit of creating a custom controller factory is that you’re no longer limited to parameterless constructors on your controllers. At this point you might be asking yourself, “How would I go about supplying parameters to a controller’s constructor?” Thanks to the extensibility of the DefaultControllerFactory and StructureMap, you don’t have to. When you declare a parameterized constructor for your controllers, the dependencies are automatically resolved when the controller is resolved in the new controller factory.

As you can see in Figure 11, I’ve added an IEmployeeService parameter to the HomeController’s constructor. When the controller is resolved in the new controller factory, any parameters required by the controller’s constructor are automatically resolved. This means you don’t need to add the code to resolve the controller’s dependencies manually—but you can still use fakes, as discussed earlier.

Figure 11 Resolving the Controller

public class HomeController : Controller {
  private readonly IEmployeeService _employeeService;
  public HomeController(IEmployeeService employeeService) {
    _employeeService = employeeService;
  }
  public ActionResult Index() {
    return View();
  }
  public ActionResult DisplaySalary(long id) {
    decimal salary = _employeeService.CalculateSalary(id);
    return View(salary);
  }
}

By using these practices and techniques in your ASP.NET MVC applications, you’ll position yourself for an easier and cleaner TDD process.


Keith Burnell is a senior software engineer with Skyline Technologies. He’s been developing software for more than 10 years, specializing in large-scale ASP.NET and ASP.NET MVC Web site development. Burnell is an active member of the developer community and can be found on his blog (dotnetdevdude.com) and on Twitter at twitter.com/keburnell.

Thanks to the following technical experts for reviewing this article: John Ptacek and Clark Sell