On my current project we have been using Unity as a Dependency Injection Container. Previously to this project I had always created constructor overloads, so any dependencies could be injected for testing or replacement. Typically what I might have done would have looked something like this:
public class MessageReceivingService : IMessageReceivingService
{
internal IMessageProcessor _MessageProcessor;
internal IMessageRepository _MessageRepository;
public MessageReceivingService()
: this(new MessageProcessor(), new MessageRepository())
{ }
public MessageReceivingService(IMessageProcessor messageProcessor, IMessageRepository messageRepository)
{
this._MessageProcessor = messageProcessor;
this._MessageRepository = messageRepository;
}
}
The above allowed me to inject and change my dependencies. In a test I’d create mock objects for the dependent objects and call the constructor that takes the dependencies as parameters. The constructor with no parameters creates the default dependencies. A typical unit test looked like the below:
private IMessageProcessor _MessageProcessorMock;
private IMessageRepository _MessageRepositoryrMock;
[TestInitialize]
public void Setup()
{
this._MessageProcessorMock = MockRepository.GenerateMock<IMessageProcessor>();
this._MessageRepositoryrMock = MockRepository.GenerateStub<IMessageRepository>();
}
[TestMethod]
public void Checking_That_Some_Behavior_Works_Test()
{
//--Arrange
MessageReceivingService serviceToTest =
new MessageReceivingService(this._MessageProcessorMock, this._MessageRepositoryrMock);
Message testMessage = new Message();
//--Act
serviceToTest.ProcessMessages(testMessage);
//--ASSERT
this._MessageProcessorMock.AssertWasCalled(imd => imd.SaveMessage(Arg<PostOffice.Data.Message>.Is.Same(testMessage)));
}
This allowed me to unit test and inject mocks. I was really only trying to allow myself the ability to inject mocks in unit testing. If it ever came up I could use the constructor overloads to override the default dependencies, but I was not that worried, that happened very infrequently.
What I did realize, and did not like, was that every time a dependency was added, I had to go change all my constructor calls in my unit test to allow for the new dependency. That was a pain, but not painful enough to make me change anything apparently.
Now that I started using Unity for DI The above class becomes this:
public class MessageReceivingService : IMessageReceivingService
{
internal IMessageProcessor _MessageProcessor;
internal IMessageRepository _MessageRepository;
internal IUnityContainer _Container;
public MessageReceivingService()
: this(new ConfiguredUnityContainer())
{ }
public MessageReceivingService(IUnityContainer container)
{
this._Container = container;
this._MessageProcessor = this._Container.Resolve<IMessageProcessor>();
this._MessageRepository = this._Container.Resolve<IMessageRepository>();
}
}
ConfiguredUnityContainer is just a class extending UnityContainer that loads types from a default container in configuration. The above allows for an existing container to be passed in, or for a new one to be created and used. I wasn’t crazy about having dependencies to unity in my constructor, but I consoled myself since the dependencies were on the IUnityContainer interface and a class I had extended from UnityContainer.
It was in my unit tests that I realized how this was really going to help me. My unit test above now changed to this:
private IMessageProcessor _MessageProcessorMock;
private IMessageRepository _MessageRepositoryrMock;
[TestInitialize]
public void Setup()
{
this._MessageProcessorMock = MockRepository.GenerateMock<IMessageProcessor>();
this._MessageRepositoryrMock = MockRepository.GenerateStub<IMessageRepository>();
}
[TestMethod]
public void Checking_That_Some_Behavior_Works_Test()
{
//--Arrange
IUnityContainer container = new UnityContainer();
container.RegisterInstance<IMessageProcessor>(this._MessageProcessorMock);
container.RegisterInstance<IMessageRepository>(this._MessageRepositoryrMock);
MessageReceivingService serviceToTest =
new MessageReceivingService(container);
Message testMessage = new Message();
//--Act
serviceToTest.ProcessMessages(testMessage);
//--ASSERT
this._MessageProcessorMock.AssertWasCalled(imd => imd.SaveMessage(Arg<PostOffice.Data.Message>.Is.Same(testMessage)));
}
The first thing I realized was that I would no longer have to change my constructor if I added a dependency! Now my only constructor overload takes an IUnityContainer. I just set my dependencies in the test code, setting my mock objects as the served up dependencies. No matter how many dependencies I add or remove my constructors will never change.
As an added bonus, I can now replace dependencies on the fly. If I deliver a container that is mapped in a config file, I only have to change the config file to change served up dependencies. I was not really that worried about changing dependencies on the fly since it seemed to happen so rarely, but I certainly do not mind that it is now easy to do should the need arise.
I probably should have realized there was more value to a DI container then just serving up mocks in tests, but even in this context the DI container made my life easier. I have to say I really like the combination of Unity and RhinoMocks. I’m kicking myself for not looking into this myself before Unity was forced on me on a project!