MVC 4 TDD, IoC and Mocking

7th May 2012

Summary:
In this article we review how to create a simple MVC 4 application using a Test Driven Development (TDD) approach. We'll use the Inversion of Control (IoC) pattern, along with Microsoft's Unity Dependency Injection (DI) container and the Moq mocking framework. We start by considering the typical Red, Green, Refactor TDD cycle, and why IoC and mocking are a desirable and logical consequence of TDD.

Introduction

For most professional software developers, the word "Test" is normally (or, at least, for many years it was) associated with the painful process where a group of sadists (the "Test Team") subjects perfect software to unreasonable torture until it breaks. Whereupon, the Test Team gleefully report that the software is even less stable than the last time they tested it. So, "Test" is a word loaded with meaning, and thus taking a "test-driven" approach to development does not sound appealing.

However, TDD should really have been termed Design by Example, which sounds much better (see the article It's Not TDD, It's Design By Example by Brad Wilson) and perhaps more accurately describes the approach. That said, TDD has become an accepted and well-recognised term, so we'll stick with it for the purposes of this article.

Straight away we ought to state that TDD is not a testing methodology, it's a design and development methodology! TDD emphasises an iterative development cycle where requirements are created in the form of unit tests, and each test is written first - before the code that defines interfaces, services, business logic, or UI. Typically, for each work item (e.g. a particular new feature) the developer will use a three-phase (Red, Green, Refactor) cycle, with each cycle being of short duration (e.g. an hour):

  • Red: write a unit test that fails
    • First, make sure you understand the requirements for the work item
    • Design/imagine how you'd like the feature to be implemented, then write the test code as though the code existed
    • Create just the necessary interfaces and 'stubs' (or use a Mocking framework - see below) so the test code compiles
    • Run the test - it will fail because the 'real code' has not yet been written. However, this verifies our mocked code isn't working by accident, which could potentially provide a 'false positive' at a later stage in development
  • Green: make the minimum changes required to pass the test
    • add the minimum code required to make the test pass - make use of mocking or hard-code method return values
    • don't add error handling code - do this later, again driven by specific tests
    • re-run all unit tests (regression testing) to ensure you haven't broken anything
  • Refactor: improve design, add business and data persistence logic, etc.
    • gradualy replace stubbed or mocked code with real-world implementation logic
    • improve the design, etc.
    • re-run tests to ensure eveything still works

It's interesting to note that this deceptively simple approach actually encapsulates a major change in the way we approach the task of writing software. Normally we ask the question, "How will I write the code to create the solution?". With TDD the question becomes, "How will I know I've solved the problem?". As J. Timothy King says in his article Twelve Benefits of Writing Unit Tests First: "We're taught to assume we already know how to tell whether our solution works. It's a non-question. Like indecency, we'll know it when we see it. We believe we don't actually need to think, before we write our code, about what it needs to do. This belief is so deeply ingrained, it's difficult for most of us to change."

Assuming we as developers are able to make this mental shift in approach, what benefits are we likely to see?

  • Design: being able to run automated unit tests forces us up-front to design a system composed of loosely-coupled components (e.g. separation of concerns)
  • Reassurance: re-running the unit tests assures us that any change we make hasn't broken anything
  • Team-working: re-running all tests (e.g. at the end of the day) is a good way of picking up any breaking-changes at an early stage
  • Documentation: tests actually document how the system works (and they can't be out-of-date)
  • Metrics: tests provide a practical measure of progress (e.g. "the system passes 78 of 100 tests")

TDD in Action - an MVC 4 Demo App

To look at TDD in practice, we'll develop a very simple "Fish" application using the following:

  • Microsoft Visual Studio 2010 with the MVC 4 framework - download MVC 4 here (or use Visual Studio 11 Beta, which includes MVC 4).
    Note that MVC 3 could equally well be used - we're not using any version 4-specific features
  • Microsoft Entity Framework 4 (we'll get the latest version using the NuGet Package Manager in Visual Studio)
  • Microsoft Unity dependency injection container (we'll get it using NuGet)
  • The Moq mocking framework (we'll get it using NuGet)

Our simple 'MvcFishApp' will be iteratively developed as follows:

  • There will be a simple home page with a link that takes the user to another page that displays a list of fish
  • Initially, units tests will use the mocking framework to return the list of fish
  • We'll use the repository pattern to de-couple the data persistence layer from the controller
  • The app will start off using a simple in-memory implementation of the data, and then move on to use the entity framework to get data from a SQL database
  • The dependency injection container will be used in conjunction with a web.config setting to declaratively configure the actual repository we want to use
  • Using the factory pattern we'll create a controller factory and hook it into the MVC framework

To get started, open Visual Studio and create a new MVC 4 project (and when prompted, choose the 'Empty' template) - I named my project 'MvcFishApp':

Next, right-click on the solution node in Solution Explorer and select Add New Project. Add a new Test project:

Rename the default test to HomeUnitTest.cs and setup the following test method for the HomeController (which doesn't exist yet). Note that you'll also need to add references to the main project and to version 4 of System.Web.Mvc.

  using System;
  using System.Text;
  using System.Collections.Generic;
  using System.Linq;
  using Microsoft.VisualStudio.TestTools.UnitTesting;
  using System.Web.Mvc;
namespace TestProject1 { [TestClass] public class HomeUnitTest { [TestMethod] public void TestHomeControllerView() { var controller = new HomeController(); // Won't compile var result = controller.Index() as ViewResult;
// Test we're using the default view name Assert.AreEqual("", result.ViewName); } } }

Now, as we're using a TDD approach, we let the tests drive the design of our application. Becuase the HomeContoller class doesn't yet exist, clearly the test code won't compile. Obviously the simplest thing to do would be to create a default HomeController. However, let's see how a mocking framework can help up mock-up a non-existant component.

Right-click the Test project in Solution Explorer and select Manage NuGet Packages:

Search for "Moq" and then install it:

This appears to add a reference to the Moq assembly. However, with my setup the reference didn't appear to work correctly (I couldn't actually access any of the types in the assembly). If you see the same thing, select the Moq reference and copy the assembly path from the Path property. Now manually add a reference to the assembly - you should now be able to add a using Moq statement to the test class.

Mocking frameworks allow us to create mock objects and then define behaviours for those objects. Clearly this type of functionality is extremely useful when we quickly want to 'mock-up' default values and results for unit tests. As we stated earlier, with a TDD approach, we want to "design/imagine how you'd like the feature to be implemented, then write the test code as though the code existed". Mocking frameworks, such as Moq, allow us to do this.

For example, when we implement our HomeController class we'll want it to have a method that responds to the Index action. So, we can define a simple interface for our HomeController like so (I added IHomeController.cs to the Models folder of the main MvcFishApp project, but you can place it anywhere that seems logical):

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Web;
  using System.Web.Mvc; 
  
namespace MvcFishApp.Models { public interface IHomeController { ActionResult Index(); } }

We can now refine our unit test as follows:

  :
  :
  using Moq;
  using MvcFishApp.Models;
  using MvcFishApp.Controllers;

  namespace TestProject1
  {
	  [TestClass]
	  public class HomeUnitTest
	  {
		  [TestMethod]
		  public void TestHomeControllerView()
		  {
			  //var controller = new HomeController();
			  // Create a new mock controller based on the IHomeController interfce
			  var controller = new Mock<IHomeController>();

			  // Configure the interface's Index() method to return a ViewResult
			  controller.Setup(c => c.Index()).Returns(new ViewResult());

			  //var result = controller.Index() as ViewResult;
			  // Call the mocked Index() method - note access is via controller.Object
			  var result = controller.Object.Index() as ViewResult;

			  // Test we're using the default view name
			  Assert.AreEqual("", result.ViewName);  
		  }
	  }
  }

Notice how we've commented out some of the original test code, and replaced it with the construction of a Mock object that uses the IHomeController interface. We setup the behaviour of the Index() method and then use the controller by making a call to the (mock) Index() method, via controller.Object.Index(). Finally, we can test the object's behaviour through an Assert().

If we run the test (Test | Run | All Tests in Solution) we should see it passes:

Now let's carry out the Refactor part of the Red, Green, Refactor cycle. In the normal way, right-click the Controllers folder in the main project and select Add Controller. Name the controller HomeController (and use the Empty controller scaffolding template):

To keep our HomeController in-step with our IHomeController interface, modify the generated class to implement the IHomeController interface:

  :
  :
  using MvcFishApp.Models;
  
  namespace MvcFishApp.Controllers
  {
	  public class HomeController : Controller, IHomeController
	  {
		  //
		  // GET: /Home/
  
		  public ActionResult Index()
		  {
			  return View();
		  }
  
	  }
  }

Create a view for the Index action by right-clicking anywhere inside the definition of HomeController.Index() and selecting Add View.

We can now update our unit test to remove the mocked code:

  [TestMethod]
  public void TestHomeControllerView()
  {
	  var controller = new HomeController();
	  var result = controller.Index() as ViewResult;

	  // Test we're using the default view name
	  Assert.AreEqual("", result.ViewName);  
  }

We've now been through a simple Red, Green, Refactor cycle. Re-running the test should show it passes, and running the app should show the default index page. All we need to do now is add a link to the (non-existent) Fish index page in our home controller's index view:

  @{
	  ViewBag.Title = "Index";
  }
  
  <h2>Index</h2>
  
  @Html.ActionLink("Get Fish List", "Index", "Fish")

We can now move on to designing the FishController that will display a list of fish.

Designing the FishController and FishRepository

Here's the definition of our simple Fish class - create a new class and add it to the Models folder:

  namespace MvcFishApp.Models
  {
	  public class Fish
	  {
		  public int ID { get; set; }
		  public string Name { get; set; }
		  public string Description { get; set; }
	  }
  }

Note that we could have used an interface to start creating our Fish-based tests, but the definition of the Fish class is so simple (it doesn't contain anything other than auto-properties) that we would gain nothing by doing so.

Let's imagine what we want and write the tests to drive the process:

  • When the user arrives at the Index action for Fish controller we want to see a list of all the Fish in our 'repository'
  • So, the controller will get a List<Fish> from a repository of some sort and pass it to the Fish Index view for rendering
  • We want to be able to start testing our app without having to create a SQL database, but later we want to be able to plug-in the database without having to change any of the controller or view code - this means we'll need to work via an interface

First, create a default Fish controller (using the Empty scaffolding template) and then create a default View for the Fish controller's Index() action (we could mock this, but it's quicker to get Visual Studio to generate code stubs at this point). Here's our first-pass attempt at writing two tests (we added a new unit test called FishUnitTest.cs):

  namespace TestProject1
  {
	  [TestClass]
	  public class FishUnitTest
	  {
		  [TestMethod]
		  public void TestFishControllerView()
		  {
			  var controller = new HomeController();
			  var result = controller.Index() as ViewResult;
  
			  // Test we're using the default view name
			  Assert.AreEqual("", result.ViewName);
		  }
		  
[TestMethod] public void TestIndexHasListOfFish() { var controller = new FishController(); var result = controller.Index() as ViewResult; var fish = (List<Fish>)result.ViewData.Model; // Test the view models contains a list of fish Assert.IsNotNull(fish, "The list of fish does not exist"); } } }

If we run the new Fish controller tests we'll see that the first test passes, but, as expected, the second test fails:

We now need to add the minimum code we can to get our second test to pass. To do this let's create an interface for a repository that will do all the work of interacting with whatever data store we're using. Here's the interface (add it to the Models folder in the main project):

  namespace MvcFishApp.Models
  {
	  public interface IFishRepository
	  {
		  List<Fish> GetAllFish();
		  Fish GetFish(int id);
		  void Create(Fish fish);
		  void Delete(int id);
		  void SaveChanges();
	  }
  }

We can now do some mocking in our unit test aginst the new interface:

  [TestMethod]
  public void TestIndexHasListOfFish()
  {
	  var mockFishRepository = new Mock<IFishRepository>();

List<Fish> mockFish = new List<Fish>(); mockFish.Add(new Fish() { ID = 0, Name = "Cod", Description = "Salt Water" }); mockFish.Add(new Fish() { ID = 0, Name = "Pike", Description = "Fresh Water" }); mockFish.Add(new Fish() { ID = 0, Name = "Bass", Description = "Salt Water" });
// Setup mock behavior for the GetAllFish() method in our repository mockFishRepository.Setup(x => x.GetAllFish()).Returns(mockFish);
// ISSUE: We now need to pass the repository into the controller like this: var controller = new FishController(mockFishRepository.Object); // Won't compile yet!
var result = controller.Index() as ViewResult; var fish = (List<Fish>)result.ViewData.Model;
// Test the view model contains a list of fish Assert.IsNotNull(fish, "The list of fish does not exist"); Assert.IsTrue(fish.Count == mockFish.Count); }

However, as we can see from the above, we now need to add a non-default constructor to our FishController to allow us to pass the repository. We also need to store the repository and then use it in the Index() method to get a list of fish:

  using MvcFishApp.Models;
  
  namespace MvcFishApp.Controllers
  {
	  public class FishController : Controller
	  {
		  private IFishRepository m_repository;

public FishController(IFishRepository repository) { m_repository = repository; }
// // GET: /Fish/ public ActionResult Index() { // Use the repository to get a list of fish var model = m_repository.GetAllFish(); return View(model); } } }

If we re-run our test it should now pass. Thanks to the Moq framework we were able to construct an object based on the IFishRepository interface, and setup a behaviour (and some mock data) for the GetAllFish() method. Once we passed the repository to the FishController it was able to use it to return a list of fish. However, we have introduced an issue - this can be seen if we actually run the app and use the link to go to the Index() action for the FishController:

By default, the MVC framework expects controllers to have a parameterless constructor. Because we added a constructor that takes an IFishRepository we've broken the app. There are, of course, several ways around this. We could create a class that implements the IFishRepository interface (and returns some test data), explicitly add a parameterless constructor, and then create an instance of the IFishRepository-derived object in the constructor. However, that would break our separation-of-concerns approach as it would require the controller to known about what kind of concrete repository was wanted.

A second type approach is a little more complex, but very much more flexible, while preserving our the separation of concerns between classes.

A Controller Factory, Inversion of Control and Dependency Injection

In order to keep our application's key classes loosely-coupled we need to:

  1. Keep the Fish controller's parameterized (IFishRepository) constructor
  2. Find a way to get the MVC framework to accept a controller which doesn't have a parameterless constructor
  3. Create one or more classes that implement IFishRepository, and find a way of configuring which implementation should be used
  4. Find some mechanism for passing an object the implements IFishRepository to the Fish constructor

Before moving on to tackle these issues, we need to take a moment to consider some important design concepts and patterns that have a direct bearing on what we're trying to achieve: Inversion of Control (IoC), Dependency Injection (DI) and the Factory.

In object-oriented (OO) programming, we create objects that have relationships to other objects. We tend to end up with "consumer" classes that rely on services provided by other classes. Typically, the consumer class will create and configure instances of the required services. As the complexity of a system grows, the inter-dependencies between consumers and services (and dependencies between services) also grows, requiring the consumer to somehow manage the complexity. This also starts to break down the black-box (separation-of-concerns) nature of the OO ecostructure - the consumer needs to know more about each of the services.

IoC is a design pattern which seeks to invert this arrangement, the key principle being that a consumer object never directly creates concreate instances of the services or objects on which it relies (thus, inverting the 'normal' control process). The consumer uses a shared interface for each service, and each service implements the interface. Furthermore, DI (which is one way of implementing the IoC pattern) means that an external third-party is responsible for creating the consumer's dependent services and then injecting them (actually, passing them as arguments to a constructor or method) into the consumer. For example:

With all this in mind, let's go back to our list of issues and tackle each in order. First, we can actually hook into the MVC framework's controller creation process by adding some code to the Global.asax.cs Application_Start() method. Remember that this method is called once when ASP.NET creates our application.

  public class MvcApplication : System.Web.HttpApplication
  {
	  :
	  :
	  protected void Application_Start()
	  {
		  AreaRegistration.RegisterAllAreas();

		  RegisterGlobalFilters(GlobalFilters.Filters);
		  RegisterRoutes(RouteTable.Routes);

BundleTable.Bundles.RegisterTemplateBundles();
// Use our custom controller factory to create the appropriate controller ControllerBuilder.Current.SetControllerFactory(new ControllerFactory()); } }

By implementing our ControllerFactory class and passing it to SetControllerFactory() we can control the creation process. Here's one way of implementing the custom controller factory (again, I added the class to the Models folder):

  public class ControllerFactory :  DefaultControllerFactory
  {
	  public override IController CreateController(
System.Web.Routing.RequestContext requestContext,
string
controllerName) { try { if (!controllerName.Equals("Fish")) return base.CreateController(requestContext, controllerName);
// Won't compile - need to implement InMemoryFishRepository return new FishController(new InMemoryFishRepository()); } catch { return base.CreateController(requestContext, controllerName); } } }

All we need to do is use DefaultControllerFactory as a base class and override the CreateController() method. We check to see if the view to create is a Fish controller, if not we just call the base class implementation (which will look for a parameterless constructor). In the case of a Fish controller, we create a FishController, and pass in an instance of a class that implements IFishRepository.

Clearly the code won't compile, as we haven't created the InMemoryFishRepository class. We can create a simple implementation as follows:

  public class InMemoryFishRepository : IFishRepository
  {
	  public List<Fish> GetAllFish()
	  {
		  var fish = new List<Fish>();
		  fish.Add(new Fish() { ID = 0, Name = "Cod", Description = "Salt Water" });
		  fish.Add(new Fish() { ID = 1, Name = "Pike", Description = "Fresh Water" });
		  fish.Add(new Fish() { ID = 2, Name = "Bass", Description = "Salt Water" });
  
		  return fish;
	  }

	  public Fish GetFish(int id)   { throw new NotImplementedException(); }
	  public void Create(Fish fish) { throw new NotImplementedException(); }
	  public void Delete(int id)    { throw new NotImplementedException(); }
	  public void SaveChanges()     { throw new NotImplementedException(); }
  }

Our custom ControllerFactory code will now compile. All we need to do now is add code to our Fish Index view to display the list of fish:

  @model List<MvcFishApp.Models.Fish>
  @using MvcFishApp.Models;

  @{
	  ViewBag.Title = "Index";
  }

  @foreach (Fish fish in Model)
  {
	  @Html.DisplayFor(x => fish.ID);
	  <span>&nbsp;</span>
	  @Html.DisplayFor(x => fish.Name);
	  <span>&nbsp;</span>
	  @Html.DisplayFor(x => fish.Description);
	  <br />
  }

Running the application and accessing the Fish Index action produces:

Everything works - let's see how far we've got with solving the list of issues:

  1. Keep the Fish controller's parameterized (IFishRepository) constructor - DONE
  2. Find a way to get the MVC framework to accept a controller which doesn't have a parameterless constructor - DONE
  3. Create one or more classes that implement IFishRepository - DONE, and find a way of configuring which implementation should be used - NOT DONE
  4. Find some mechanism for passing an object the implements IFishRepository to the Fish constructor - DONE

So, we're nearly there. We just need a nice, clean way of configuring the type of repository to use (because later on we will want to change it to use a SQL-based repository). Here's how we might look to implement the required configuration by adding a key to the appSettings section of web.config and updating our controller factory:

  public class ControllerFactory :  DefaultControllerFactory
  {
	public override IController CreateController(
System.Web.Routing.RequestContext requestContext, string controllerName) { try { if (!controllerName.Equals("Fish")) return base.CreateController(requestContext, controllerName); // Need to add an entry to the web.config <appSettings> section: // <add key="Repository" value="InMemoryFishRepository"/> string repositoryTypeName = System.Configuration.ConfigurationManager.AppSettings["Repository"]; // Get the actual .NET type of repository we need Type repositoryType = Type.GetType("MvcFishApp.Models." + repositoryTypeName); // Create an instance of the repository type we need var newRepository = (IFishRepository)Activator.CreateInstance(repositoryType); // Create the controller and inject the repository dependency return new FishController(newRepository); } catch { return base.CreateController(requestContext, controllerName); } } }

This works, but we can approach the creation of dependencies in another way. The use of dependency injection containers like Castle Windsor, StructureMap, Spring.NET, Ninject, and Microsoft's Unity has become a common technique. Essentially, all DI containers do the same thing: they create instances of objects and automatically inject the required dependent objects. Where dependencies are based on interfaces, the DI container allows us to pre-configure a "when you see this interface, I want one of these objects that implements the interface" mapping.

So, in our case, we could register a mapping between IFishRepository and InMemoryRepository, and then get the DI container to create our FishController, automatically creating and injecting the necessary repository object to the controller's constructor. Neat!

Let's see how this works in practice. First, in the same way we added the Moq package to our test project, we need to use Visual Studio's NuGet package manager to add Unity - just search for Unity and install it:

We can now update our controller factory like so:

  public class ControllerFactory :  DefaultControllerFactory
  {
	  public override IController CreateController(
		System.Web.Routing.RequestContext requestContext, 
		string controllerName)
	  {
		  try
		  {
			  if (!controllerName.Equals("Fish"))
				  return base.CreateController(requestContext, controllerName);

			  // Need to add an entry to the web.config <appSettings> section:
			  // <add key="Repository" value="InMemoryFishRepository"/> 
			  string repositoryTypeName =
				  System.Configuration.ConfigurationManager.AppSettings["Repository"];

			  // Get the actual .NET type of repository we need
			  Type repositoryType = Type.GetType("MvcFishApp.Models." + repositoryTypeName);

			  // Create the container
			  var container = new UnityContainer();

			  // Setup a mapping between IFishRepository and the configured concrete repository type
			  container.RegisterType(typeof(IFishRepository), repositoryType);

			  // Create the FishController and auto-inject the required 
			  // repository dependency into its constructor...
			  return container.Resolve<FishController>();
		  }
		  catch
		  {
			  return base.CreateController(requestContext, controllerName);
		  }
	  }
  }

We're now in good shape for when we want to add another type of (say SQL-based) repository: we'll be able to add it without any changes to our existing code! To prove it, we can create a simple SQL database that mirrors the structure of the Fish class (ID, Name, Description). Then add the necessary database connection string to web.config. Finally, we can implement the DBFishRepository class, which uses the entity framework (you may need to use NuGet to obtain the latest version of the Microsoft entity framework) to access the database:

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Web;
  using System.Data;
  using System.Data.Entity;
  using System.Data.EntityClient;
  using System.Data.EntityModel;
  using System.ComponentModel.DataAnnotations;
  
  namespace MvcFishApp.Models
  {
	  public class DBFishRepository : DbContext, IFishRepository
	  {
		  // List of Fish - automatically populated by the EF
		  // as long as the property is public and of type DbSet<T>
		  public DbSet<Fish> Fishes { get; set; }

		  public int ID { get; set; }
		  public string Name { get; set; }
		  public string Description { get; set; }

		  public List<Fish> GetAllFish() { return Fishes.ToList<Fish>(); }
		  public Fish GetFish(int id)    { throw new NotImplementedException(); }
		  public void Create(Fish fish)  { throw new NotImplementedException(); }
		  public void Delete(int id)     { throw new NotImplementedException(); }
		  public new void SaveChanges()  { throw new NotImplementedException(); }

		  // Specify the name of the connection string in the call to the base class constructor
		  public DBFishRepository() : base("Fish") {}

		  protected override void OnModelCreating(DbModelBuilder modelBuilder)
		  {
			  // Map the table name to our actual table name ("Fish")
			  modelBuilder.Entity<Fish>().ToTable("Fish");
		  }
	  }
  }

All we need to do now is change the name of the repository we want to use in web.config:

  <!-- Configure the repository required (DBFishRepository or InMemoryFishRepository) -->
  <add key="Repository" value="DBFishRepository"/>   

If we run the app we should see that without any changes to our existing code, the application gets a list of fish from the database.

Summary:
In this article we reviewed how to create a simple MVC 4 application using a TDD approach. We saw how to make practical use of the IoC pattern, the Unity dependency injection container and the Moq mocking framework.