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!