.NET and me Coding dreams since 1998!

23Dec/085

Dependency injection in real world

Patrick left a comment on one of my previous blog posts asking a couple of very interesting questions that I’ve been asking myself too:

Is service locator legitimate way of doing IoC?

(I’ll use example code from that blog post as a base for my today blog post so in case you are idle enough you can go and check it out)

Dependency injection primer

Let me start with an example how “real” dependency injection implementation code from my blog post could look like:

using System;
using System.Collections.Generic;

namespace Example.UserManager
{
    public class UserManagerIoC
    {
        private readonly IUserProvider userProvider;

        public UserManagerIoC(IUserProvider userProvider)
        {
            this.userProvider = userProvider;
        }

        public int NumberOfUsersActiveInLast10Days(string userName)
        {
            var userCollection = this.userProvider.GetUserCollection();
            int result = 0;
            foreach (User user in userCollection)
            {
                if (user.Name.StartsWith(userName) && user.LastActivity > DateTime.Now.AddDays(-10))
                    result++;
            }
            return result;
        }
    }
}

As we can see from the simple code above, code has one constructor which accepts the IUserProvider parameter and then stores its pointer to a field  so it can be used  later in a method which performs some kind of business logic.

Key concept here to be noticed is that class have literally no clue where from and how userProvider would get injected.

How DI based unit test looks like?

I’ll use Microsoft Unity and Rhino mocks to write a test for the dependency injection primer.

Here it is:

using System.Collections.Generic;
using Example.UserManager;
using Microsoft.Practices.Unity;
using NUnit.Framework;
using Rhino.Mocks;

namespace UserManager.Test.IoC
{
    [TestFixture]
    public class UserManagerTestIoC
    {
        private MockRepository mockRepository;
        private IUnityContainer unityContainer;

        [SetUp]
        public void Test_Init()        
        {
            this.mockRepository = new MockRepository();
            this.unityContainer = new UnityContainer();
        }

        [Test]
        public void GetActiveUsers_TestCaseOfZeroUsers_WouldReturnEmptyCollection()
        {
            var userProvider = this.mockRepository.DynamicMock<IUserProvider>();
            // injecting to unity container mocked instance of user provider
            this.unityContainer.RegisterInstance(userProvider);
            
            using (this.mockRepository.Record())
            {
                Expect.Call(userProvider.GetUserCollection())
                    .Return(new List<User>());
            }
            using (this.mockRepository.Playback())
            {
                // using IoC container for UserManager construction 
                var userManager = this.unityContainer.Resolve<UserManagerIoC>();
                
                // and then performing tested code 
                int numberOfUsers= userManager.NumberOfUsersActiveInLast10Days("X");
                Assert.IsTrue(numberOfUsers == 0);
            }
        }  
    }
}

What I did in that test:

  • I am instantiating UnityContainer in test set up to be used as IoC container.
  • In first line of test  method I am using Rhino mocks to create mock of IUserProvider and then I inject that mock to Unity IoC container
  • In a first line of recording block, I set expectation that empty user collection would be returned
  • In playback block, I get an instance of UserManagerIoC class by using IoC container Resolve factory method. (KEY POINT)
  • IoC container would then:
    • examine the constructor of UserManagerIoC class,
    • see that IUserProvider parameter is requested
    • try to find in IoC container registered service implementing IUserProvider interface
    • mocked instance we injected at the beginning of the test would be found
    • mocked instance would be injected to UserManagerIoC
  • Method would be executed and the expected number of users checked

NOTE #1: You could get away from explicit dependency mocking by using AutoMockingContainer but I decide to do it anyhow in this post in order to increase example readability.

NOTE #2: You could also opt to use var userManager = new UserManager(userProvider) but this is not something typically you would do because userProvider can have it’s own dependencies and so on… Not using IoC container in the test would mean not using one of its most important features: auto dependency resolution.

Dependency injection upsides and downsides

As we can see, we were able to keep UserManager light and ignorant about IoC infrastructure, while utilizing the benefits dependency injection provides us (increased testability in this example)

Still there are couple of problems (not sure if I can call them like this) related to this implementation which I’ve witnessed in last couple of months and which can be summarized as:

  • Brownfield scenarios

    UserManager is already existing class built without having dependency injection on mind (no constructor exposing abstracted dependencies). While it is hard to sell the business value of refactoring UserManager internals to expose dependencies through constructor (sell tagline: to test it) it is mission impossible getting approval for updating all of the million places  currently doing the UserManager um = new UserManager() to become unityContainer.Resolve<UserManager>() (Sith language : “What’s the business value?”) and without that change no DI going to happen.

  • Code monkey scenarios

    Vast majority of developers I know don’t get the IoC, TDD etc, which means that one would spend ton of time answering the

    “Why I can not just new the instance?”, “This is clearly an overkill…”, “Here it is him with his damn patterns making my life miserable”, “Why I need to decouple DB from my  unit tests at all?”..

    Although this reason might look “not-so-important”, if you are not lucky to work in TDD friendly environment, if you are working in company which DEV teams span across the globe this could be real show stopper.

  • “TDD == unit test”

    If you are doing unit tests AFTER the code is been done then it is very hard to sell to PMs the need for “all that complexity”.

    In other words, if they don’t get that in TDD the most important thing is not the “T” (test) but the “DD” (driven design) whole DI thing start to get harder to be sold

  • “Why IoC framework X?”

    ”Why UnityContainer?” “Why not Castle?” “Why not Spring?” “Why not StructureMap?” “On my previous job I worked with XYZ and it is the best…”

 

ServiceLocator based dependency injection

Luckily, I think I found a way how to go around the restrictions mentioned above with keeping the dependency injection in place and high testability. I’ve wrote in more details in my DFT blog post series so here I’ll just summarize it…

The key points that solution has to achieve are:

  1. Core code implementation has to utilize dependency injection
  2. Code has to be “open for testing” but “close for development”  (yes, I am aware how stupid this might sound and it it stupid thing – details bellow )
  3. DI enabling existing code is not allow to cause any breaking compatibility issues (KIC - “keep it cheap” design principle)
  4. No dependency on any particular IoC framework

Lets take a look at the same primer I’ve done with DI this time implemented using service locator

using System;
using Facade;

namespace Example.UserManager
{
    public class UserManagerSL
    {
        private readonly IUserProvider userProvider;

        public UserManagerSL(): this (ServiceLocator.Retrieve<IUserProvider>())
        {
        }

        internal UserManagerSL(IUserProvider userProvider)
        {
            this.userProvider = userProvider;
        }

        public int NumberOfUsersActiveInLast10Days(string userName)
        {
            var userCollection = this.userProvider.GetUserCollection();
            int result = 0;
            foreach (User user in userCollection)
            {
                if (user.Name.StartsWith(userName) && user.LastActivity > DateTime.Now.AddDays(-10))
                    result++;
            }
            return result;
        }
    }
}

Main differences (compared to dependency injection primer) are:

  • We still have public parameter less constructor

    That parameter less  constructor uses ServiceLocator to retreive instace of IUserProvider on a same way UnityContainer retrieved it in previous test.

    ServiceLocator is just a Facade wrapper around IoC container encapsulating the type of container and hiding not used features.

    Achieved design goal: “Keep it cheap”

    Achieved design goal: “No dependency on particular IoC framework”

  • In some bootstrapper class tied to app start event I will have to define ServiceLocator mapping for service implementing the IUserProvider so the code would work normally like it was working before the dependency injection

  • Constructor taking IUserProvider parameter is now internal.

    The assembly containing UserManagerSL class would contain next attribute

    [assembly: InternalsVisibleTo("UserManager.Test.SL")]

Result of this attribute would be that this constructor would be:

- visible to test assembly containing test methods using UserManagerSL

- not visible to any code outside of that test assembly (none of the “core DEV” would be aware of it)

Achieved design goal: “Open for test, close for development”

Achieved design goal: “Dependency injection used in code”

How ServiceLocator based test looks like?

Here are two examples how the service locator code can be tested..

“White box” service locator test style

using System.Collections.Generic;
using Example.UserManager;
using Facade;
using NUnit.Framework;
using Rhino.Mocks;

namespace UserManager.Test.SL
{
    [TestFixture]
    public class UserManagerTestSL
    {
        private MockRepository mockRepository;
        private IUserProvider userProvider;

        [SetUp]
        public void Test_Init()        
        {
            this.mockRepository=new MockRepository();

            // registering mock of IUserProvider with ServiceLocator
            this.userProvider = this.mockRepository.DynamicMock<IUserProvider>();
            ServiceLocator.InjectStub(this.userProvider);
        }

        [Test]
        public void GetActiveUsers_TestCaseOfZeroUsers_WouldReturnEmptyCollection_WithSL()
        {
            using (this.mockRepository.Record())
            {
                Expect.Call(this.userProvider.GetUserCollection())
                    .Return(new List<User>());
            }
            using (this.mockRepository.Playback())
            {
                // using internal constructor
                var userManager = new UserManagerSL();
                int numberOfUsers = userManager.NumberOfUsersActiveInLast10Days("X");
                Assert.IsTrue(numberOfUsers == 0);
            }
        }
    }
}

In this testing style we feed the service locator with the list of internal dependencies we know it is been used by the tested code and then in our test method we totally don’t care about dependency injection (constructors used are empty, no service locator usage anywhere outside of SetUp method)

I personally don’t like this style of testing (based on intimate knowledge of tested code) but I’ve seeing it working in the past.

Using internal constructor

Second approach is based on the fact that internal constructor is accessible to test assembly which makes test built on this way very simple

using System.Collections.Generic;
using Example.UserManager;
using NUnit.Framework;
using Rhino.Mocks;

namespace UserManager.Test.SL
{
    [TestFixture]
    public class UserManagerTestSL
    {
        private MockRepository mockRepository;

        [SetUp]
        public void Test_Init()        
        {
            this.mockRepository=new MockRepository();
        }

        [Test]
        public void GetActiveUsers_TestCaseOfZeroUsers_WouldReturnEmptyCollection()
        {
            IUserProvider userProvider = mockRepository.DynamicMock<IUserProvider>();

            using (mockRepository.Record())
            {
                Expect.Call(userProvider.GetUserCollection())
                    .Return(new List<User>());
            }
            using (mockRepository.Playback())
            {
                // using internal constructor
                var userManager = new UserManagerSL(userProvider);
                int numberOfUsers = userManager.NumberOfUsersActiveInLast10Days("X");
                Assert.IsTrue(numberOfUsers == 0);
            }
        }
    }
}

In this example we don’t use at all service locator. Instead we simply inject mocked instance of user provider to internal constructor. All of the downsides of this approach (mentioned in dependency injection note #2) are applicable here to.

Using dependency injection

The best thing with my service locator based design approach is that while some of the “not so TDD skilled” developers can do testing on the first two ways, “TDD skilled” developer can still write exactly the same test as the one given in the dependency injection section of this blog post.

Check it for yourself:

        [Test]
        public void GetActiveUsers_TestCaseOfZeroUsers_WouldReturnEmptyCollectio_IoC()
        {
            var userProvider = this.mockRepository.DynamicMock<IUserProvider>();
            // injecting to unity container mocked instance of user provider
            ServiceLocator.InjectStub(userProvider);

            using (this.mockRepository.Record())
            {
                Expect.Call(userProvider.GetUserCollection())
                    .Return(new List<User>());
            }
            using (this.mockRepository.Playback())
            {
                // using IoC container for UserManager construction 
                var userManager = ServiceLocator.Retrieve<UserManagerSL>();

                // and then performing tested code 
                int numberOfUsers = userManager.NumberOfUsersActiveInLast10Days("X");
                Assert.IsTrue(numberOfUsers == 0);
            }
        }  

Summary

Most of the blog posts I’ve seen present an ideal “perfect day” situation setup  for writing the test which is not always the case in real world.

In this kind of “not-so-perfect” situations, service locator based solution I’ve presented in that blog post allowed me to increase testability and introduce TDD into existing code bases and environments not so much interested in the TDD.

Source code for this blog post can be found here.

Comments (5) Trackbacks (0)
  1. I loved this post and the previous one. One nitpick though:

    # public UserManagerSL(): this (ServiceLocator.Retrieve<IUserProvider>())  

    #         {  

    #             this.userProvider = userProvider;  

    #         }

    There’s no userProvider argument, and in fact you don’t need a body for this constructor anyway, since you’re calling the other constructor with this(…)

  2. Oh,

    here it is: the proof of how stupid copy- paste driven development can be :)

    I’ve updated the source code and blog post

    Thanks for the tip!

  3. hi,

    this article and the series of DI articles are very good written (esp. the samples are perfect).

    may i ask you a question regarding the implementation: in my project, i have a class-lib-project (CORE) where there are a lot of repositories and manager classes. i have on Resolver-Type, and if i need some sort of repository, i call Resolver.Resolve<T> …  (it s a little bit like your facade.resolver).

    this all works well.

    now i have a web-project, this instantiates the repository/manager classes of CORE. therefore this project also needs a DI container.

    this also works well.

    now, i wanted to reduce type-creations, so e.g. the user-repository should only be created one time. so i choosed to type it as singleton (with unity).

    but, because CORE instantiates a container, and web instantiates a container, i have two instances of that particular repository.

    what is your tipp to solve this part of my problem?

  4. Karli,

    make your Resolver-TYpe to be singleton (static class e.g.) and register mapping in application start event of global.asax

    Your CORE library would be loaded during the bootup in the context of web application and therefore it would be able to retreive IRepository service

    HTH,

    Nikola

  5. thank you,

    i did solve my problem a little bit different (but i think its ok) :)


Leave a comment

No trackbacks yet.