Simple MVC 4 Unit Test example using Moq and TDD

For WireTapp we are attempting to create as much of our application through the medium of Unit Tests. In other words, where possible, we are using Test Driven Development (TDD). There are definitely some issues with using TDD and MVC, mostly due to the availability of scaffolders and ORMs and the like in Visual Studio. These tools create a lot of classes and methods for you, and while usually only a bare bones implementation, they are still that, an implementation, which straight away breaks what you would call traditional TDD. With TDD you should obviously first create your tests then create your application classes and objects that enable you to get a passing test.

However, I think you would be mad not to utilise the MVCScaffolding and Entity Frameworks of this world just because they break TDD. I think a certain amount of faith can be put into these tools to not create erroneous and unnecessary code. If you want to be extra cautious you can create the most minimal implementation where possible. For example we scaffolded an initial set of controllers that only contained a single Index action. Everything else we would attempt to add to the class through TDD.

With this in mind, I’d like to put forward a modified version of TDD that I think best suits MVC 4 in Visual Studio, MVC-TDD, if you will. Instead of the traditional Test->Fail->Pass->Refactor model, I think a preliminary Scaffold stage should be included. In other words, MVC-TDD can be seen as a two step process 1. Scaffold 2. Test->Fail->Pass->Refactor. As mentioned, this scaffolding can be anything from controller scaffolding to Entity Framework domain model creation. In essence if something can be done using scaffolding-type tools instead of TDD, then scaffold first. The scaffolds are there for a reason and are generally best practice solutions. It doesn’t make sense to go the alternative route of doing all of that potentially scaffolded code through TDD. It will just slow down development and you will probably end up with a solution similar or identical the one a scaffolder would have created for you anyways.With this in mind we went ahead and created a simple Domain Model and persistence layer (as described in previous posts) containing scaffolded skeletal repositories and unit of work classes. From this we scaffolded bare bones controllers that linked to each of our repositories (our in our case unit of work wrappers, again see previous posts for more detail on this, if you wish). Anyways it was at this point that we felt it made most sense to begin TDD, i.e. step 2 of our 2 step process.

In our previous post we also noted that we added a dependency injection to our controllers. We will see now how this has greatly improved our unit test efficiency. When unit testing our controller and controller methods/actions we do not want to have to access any other area of our application. Below is an example of how we scaffolded an initial implementation of one of our controllers, remember Dependency Injection is working in the background to ensure it receives the correct concrete implementation of the interface class shown:

private IMembershipAccessor _membershipAccessor;
 
public MembersController(IMembershipAccessor membershipAccessor)
{
   _membershipAccessor = membershipAccessor;
}

So the controller expects a class of type IMembershipAccessor. As we are implementing a unit test of the controller class only, we do not want to instaniate this class or create a dummy class that inherites this interface. Our best option is to use a Mock. I know there is debate about whats a fake or a mock or a stub or whatever, for me the term Mock makes sense because what I want is an object that mocks the behaviour of a real object. The beauty of this approach is that the mock can be created and managed from within your unit test and calls no other classes in the application. For our Mocking we used the tool Moq. We installed it into the test project through Nuget.

Below is an example of how we used Moq to unit test our MembersController Index action:

Unit Test Class Constructor:

Mock<IMembershipAccessor> mockMembersAccessor;
List<Member> mockMembers;
 
public MembersControllerTests()
{
   //arrange
   mockMembersAccessor = new Mock<IMembershipAccessor>();
 
   mockMembers = new List<Member>();
   mockMembers.Add(new Member() { MemberID = 0, FirstName = "David", LastName = "Kaye" });
   mockMembers.Add(new Member() { MemberID = 1, FirstName = "John", LastName = "Smith" });
   mockMembers.Add(new Member() { MemberID = 2, FirstName = "Mary", LastName = "Jones" });
 
   mockMembersAccessor.Setup(x => x.Repo.AllMembers).Returns(mockMembers);
}

Unit Test:

[TestMethod]
public void TestIndexHasListOfMembers()
{
    // Arrange
    var controller = new MembersController(mockMembersAccessor.Object);
 
    // Act
    var result = controller.Index() as ViewResult;
    var members = (List<Member>)result.ViewData.Model;
 
    // Assert 
    Assert.IsNotNull(members, "This list of members does not exist");
    Assert.IsTrue(members.Count == mockMembers.Count);
}

As you can see in the constructor we are mocking up an implementation of the Interface we need. We pass in a list of objects that it would expect to contain and create a mock up of a method/property that it has (.Repo.AllMembers) and saying what a call to that method/property should return to us.

Then in our unit test you can see that we create an instance of the controller but pass in the mocked object instead of a real instance. We then call the index method and get its result. The index method inside of the controller looks like this:

public ActionResult Index()
{
   var model = _membershipAccessor.Repo.AllMembers;
   return View(model);
}

The index of course does not realise that the membershipAccessor object it is working with is a mocked object because the mocked object contains everything that it needs to complete its task, i.e. the mocked object contains a mock up of the .Repo.AllMembers property that we saw earlier. If all goes well the Index action should return to us our list of Mocked Members, and this is asserted in our unit test.

What I haven’t shown is how I stepped through all the TDD actions to get to this point, but you can see what’s happening, we create our test, it fails, we add our code to the index method of the controller, it passes, then we do any refactoring we see fit. Finally what I generally do once I get a passing test is add the View for that action if it isn’t already created. Testing your views isn’t something you can really do using Unit Tests or TDD, so I will cover how we went about testing these in a later post.