Setting Up MVC Using StructureMap, Moq and NUnit...Quickly
When I was first attracted to the Microsoft MVC Framework, one of my main ambitions was to develop using a more test driven approach. There are ways to include Unit testing with WebForms, but the friction was just too much to justify on the web projects I was involved with.
As soon as I started using MVC I was amazed at how easy it was to incorporate unit testing and isolation frameworks; in a way it became more of a natural process.
Here in this post I am quickly covering getting up and running with unit testing, isolation frameworks and MVC.
My tools of choice are:-
- NUnit – Testing
- Moq – Isolation framework
- StructureMap – IoC framework
This example is a simple green field site; the typical File >> New Project >> MVC application.
So we have our site, I want data from a database (in this example I won’t be bothering with creating a data store, which shows just how handy stubs can be).
I want to run a test on the data and send it off to the view, simple stuff.
In Models, I want to create a data repository, but I don’t want to code against a concrete type, I will use an interface.
public interface IRepository
{
int GetTotalOrders();
}
public class Repository : IRepository
{
public int GetTotalOrders()
{
return 55;
}
}
Here I have a simple method which in this case returns a hard coded integer.
So far so good, the site compiles.
I want the controller to handle this method call via an Order class like this.
public class Order
{
private IRepository Repository;
public Order(IRepository repository)
{
Repository = repository;
}
public int GetTotalOrders()
{
return Repository.GetTotalOrders();
}
}
As can be seen there are two SOLID principles in use here. The Order is dependent on the Repository class, but this dependency is injected in to the constructor. Also it is handed an interface and not a concrete type.
So my controller can call the GetTotalOrders method on the Order and let that handle the repository, but before all that I want a test in place that will make sure I am returning that data from the repository.
Of course in the real world I don’t want to touch the database, and in this case I don’t even have one. Here is the unit test that stubs out the repository call.
[Test]
public void GetTotalOrders_returns_56()
{
//Arrange
var repositoryMock = new Mock<IRepository>();
repositoryMock.Setup(r => r.GetTotalOrders()).Returns(56);
Order orders = new Order(repositoryMock.Object);
//Act
int expectedValue = 56;
int actualValue = orders.GetTotalOrders();
//Assert
Assert.AreEqual(expectedValue, actualValue);
}
In this case I am forcing the repository to return an integer of 56, not the 55 from the concrete class. The solution compiles and the test passes.
Great, but how do we code this for the controller.
public class HomeController : Controller
{
public HomeController()
{
}
public ActionResult Index()
{
Repository repository = new Repository();
Order orders = new Order(repository);
int totalOrders = orders.GetTotalOrders();
ViewData["TotalOrders"] = totalOrders.ToString();
return View();
}
}
This works fine, but I don’t want the Index method to be responsible of creating the Repository object, so we take that out and let the constructor handle that.
public class HomeController : Controller
{
private readonly IRepository Repository;
public HomeController(IRepository repository)
{
Repository = repository;
}
public ActionResult Index()
{
Order orders = new Order(Repository);
int totalOrders = orders.GetTotalOrders();
ViewData["TotalOrders"] = totalOrders.ToString();
return View();
}
}
Now it compiles ok, the tests run ok, but the web application fails.
This is where we need to start injecting the dependencies needed. We need both an ApplicationRegistry and Bootstrapper class.
public class ApplicationRegistry : Registry
{
public ApplicationRegistry()
{
ForRequestedType<IRepository>()
.TheDefault.Is.OfConcreteType<Repository>();
}
}
public static class Bootstrapper
{
public static void ConfigureStructureMap()
{
ObjectFactory.Initialize
(x => x.AddRegistry(new ApplicationRegistry()));
}
}
The ApplicationRegistry class reads very fluently and simply injects any occurrence of the IRepository type with the Repository concrete type.
Next we need a controller factory which inherits from the MVC DefaultControllerFactory and is called from the Application_Start in the Global.asax file.
public class StructureMapControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(Type controllerType)
{
if (controllerType == null) return null;
try
{
return ObjectFactory.GetInstance(controllerType) as Controller;
}
catch (StructureMapException)
{
System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave());
throw;
}
}
}
protected void Application_Start()
{
Bootstrapper.ConfigureStructureMap();
ControllerBuilder.Current.SetControllerFactory
(new StructureMapControllerFactory());
RegisterRoutes(RouteTable.Routes);
}
Now rebuilding and running the site we successfully retrieve the value from the repository.