Unity Singleton / Unit testing / Mocking

It’s been a while since I did a blog post (that is something I aim to fix), but just for now here is a small one.

The other day, I was confronted with a class that I had to test/mock, and it had this hardcoded dependency on a IOC container item (we are using the Unity application block) in its constructor

public interface ISecurityProvider
{
    IList Privileges { get; }
}

public class SecurityProvider : ISecurityProvider
{
    private SecurityContext context;

    public SecurityProvider()
    {
        context = IOCManager.Instance.Container.Resolve();
    }

    public IList Privileges
    {
        get { return context.Privileges; }
    }
}

Where the SecurityContext class looks like this

public class SecurityContext
{
    public SecurityContext(List privileges)
    {
        this.Privileges = privileges;
    }

    public List Privileges { get; set; }
}

And the IOC manager looks somethi

public class IOCManager
{
    private static Lazy instance = new Lazy(()=> new IOCManager());

    private IOCManager()
    {
            Container = new UnityContainer();
    }

    static IOCManager()
    {

    }

    public static IOCManager Instance
    {
        get { return instance.Value; }
    }

    public UnityContainer Container { get; set; }
}

And the IOC configuration looks like this

List privileges = new List();
privileges.Add("CanTrade");
privileges.Add("CanPrice");

SecurityContext sc = new SecurityContext(privileges);

IOCManager.Instance.Container.RegisterInstance(sc, new ContainerControlledLifetimeManager());
IOCManager.Instance.Container.RegisterType<ISecurityProvider, SecurityProvider>();

Now the question is, how do you get the singleton instance to ever return anything other than the “CanTrade” and “CanPrice”?????

The trick to this is the ContainerControlledLifetimeManager. By holding an instance of this we can use the SetValue(..) method to set a new singleton value.

Here is a full source dump

class Program
{
    static void Main(string[] args)
    {
        ContainerControlledLifetimeManager manager = new ContainerControlledLifetimeManager();

        List privileges = new List();
        privileges.Add("CanTrade");
        privileges.Add("CanPrice");

        SecurityContext sc = new SecurityContext(privileges);

        IOCManager.Instance.Container.RegisterInstance(sc, manager);
        IOCManager.Instance.Container.RegisterType<ISecurityProvider, SecurityProvider>();

        //1st singleton, should show 2 privileges
        Console.WriteLine("1st singleton");
        Console.WriteLine(IOCManager.Instance.Container.Resolve()
                            .Privileges.Aggregate((x, y) => string.Format("-{0} -{1}", x, y)));

        privileges = new List();
        privileges.Add("CanTrade");
        privileges.Add("CanPrice");
        privileges.Add("CanAutoBook");

        sc = new SecurityContext(privileges);
        manager.SetValue(sc);

        //new singleton, should show 3 privileges
        Console.WriteLine("\r\n");
        Console.WriteLine("new singleton");
        Console.Write(IOCManager.Instance.Container.Resolve()
                            .Privileges.Aggregate((x, y) => string.Format("-{0} -{1}", x, y)));
        Console.ReadLine();
    }
}

When this is run you should see the following output:

1st singleton
-CanTrade -CanPrice

new singleton
-CanTrade -CanPrice -CanAutoBook

As always here is a small demo app:

demo project.zip

Advertisements

2 thoughts on “Unity Singleton / Unit testing / Mocking

  1. John Brett says:

    Interesting approach, Sacha, and cool that you can make it work.
    However, my first thought would be that the DI architecture had failed if we ended up with a Singleton (which then itself mandates a concrete implementation of its dependency).
    Did you not have an opportunity to change the design of SecurityProvider to avoid the use of the singleton?

    • sachabarber says:

      Yeah I agree this is bad IOC for sure. Sadly it was not under our control. But yes I completely agree with you

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: