Wednesday, January 19, 2011

Using StructureMap Automocker To Make Writing Tests fun.

I have for a period of time been a big fan of Jeremy Miller’s StructureMap library for Dependency Injection/Inversion Of Control. I particularly enjoy the Auto Registration and Type Scanning features of the library.

For instance within the Data Layer a registry such as:
[sourcecode language="csharp"]
public class DataRegistry : Registry
{
public DataRegistry()
{
Scan(x => { x.AddAllTypesOf(); x.ConnectImplementationsToTypesClosing(typeof(IRepository)); x.TheCallingAssembly(); });
}
}
[/sourcecode]

This class, which inherits from StructureMap.Configuration.DSLRegistry, will scan the types in the assembly that contains the Data Registry class, adds all implementations of IQuery to the the container and connects all implementation to the open generic IRepository.

I have recently discovered another feature that makes StructureMap one of my essential tools in my Development Toolkit. The aforementioned feature is Automocker, which comes in flavours such as RhinoAutoMocker and MoqAutoMocker. Automocker repurposes an IoC container to automate the creation and attachment of mock objects to a concrete class within unit tests. Certainly is a mouthful but hopefully an example will shed some light on the some of the advantages.

Let’s say you are writing Unit Tests for a Child Sponsorship website for Worldvision (something that happens quite a bit to me) and you have a class whose responsibility is to lock a user chosen child so that the child cannot be sponsored by another user of the site.

The class could look something like this:
[sourcecode language="csharp"]
public class ChildChosenForSponsorshipCommandHandler : ICommandHandler
{
private readonly IRepository _childRepository;
private readonly IChildOnHoldTimer _childOnHoldTimer;

public ChildChosenForSponsorshipCommandHandler(IRepository childRepository, IChildOnHoldTimer childOnHoldTimer)
{
_childRepository = childRepository;_
childOnHoldTimer = childOnHoldTimer;
}

public void Handle(Child child)
{
_childRepository.PlaceChildOnHold(child);
_childOnHoldTimer.Start();
}
}
[/sourcecode]

One test which could be written for this user story is
[sourcecode language="csharp"]
[Test]
public void ShouldPlaceChildOnHoldWhenChildIsChosenForSponsorship()
{
//arrangevar mockChildRepostory = MockRepository.GenerateMock();
var mockChildOnHoldTimer = MockRepository.GenerateMock();
var childChosenForSponsorshipCommandHandler = new ChildChosenForSponsorshipCommandHandler(mockChildRepostory,mockChildOnHoldTimer);

var child = new Core.Handlers.Child();

//actchildChosenForSponsorshipCommandHandler.Handle(child);

//assertmockChildRepostory.AssertWasCalled(x => x.PlaceChildOnHold(child));
}
[/sourcecode]

The way in which can be written using StructureMap’s AutoMocker assembly is:
[sourcecode language="csharp"]
[Test]
public void ShouldPlaceChildOnHoldWhenChildIsChosenForSponsorship()
{
//arrangevar childChosenForSponsorshipCommandHandler = new RhinoAutoMocker();

var child = new Core.Handlers.Child();

var classUnderTest = childChosenForSponsorshipCommandHandler.ClassUnderTest;

//actclassUnderTest.Handle(child);

//assertchildChosenForSponsorshipCommandHandler.Get().AssertWasCalled(x=>x.PlaceChildOnHold(child));
}
[/sourcecode]

A whole ONE line less code, I’ll have that new feature out before lunch! On the surface in may not look like much but if the class under test (CUT) has three, four or more dependencies you’ve made the arranging of the Unit Test much easier. The greatest benefit of the AutoMocker that I can see is that it helps keep the content of your tests focused on what needs to be tested, the functionality of your system. It also helps to keep your tests less brittle as your objects evolve. That is, if you add another dependency as your code evolves and you’ve got 15 tests under this Test Fixture you won’t have 15 tests to fix so that you can get the green light. In other words you can concentrate on what is important the context of the next test.

No comments:

Post a Comment