Mocking Dependencies != IoC (or at least it doesn’t have to)


Since I met the concept of Inversion of Control (IoC) I’ve been a big fan!  What an elegant way to externalize dependencies and decouple a component from all the components it depends on.  No longer is a component initializing a dependency initially coupling itself in a hard way.

A nice side-effect is that an IoC-compliant component is easier to test:  you have access to all its dependencies and you can replace them with mocks.

Since then I’ve integrated some form or another of IoC pattern.  A typical implementation is to use an IoC container.  I’ve worked mainly with Unity (from Microsoft Enterprise Library) and Spring.NET.  This works marvel:  you configure all dependencies in an XML config file and you components are all independent, bound only by interfaces.

Then you do that on a big project.  You end up with a huge collection of XML config with class-name in XML.  It becomes hard to troubleshoot because component A needs component B than needs component C and bang!  component C has a property set to a type that has changed (name refactoring for instance) and now the instantiation of A fails with a phony message.

I remember reading somewhere in a Java Community that Spring was a framework to translate an XML file into an exception stack!  Ok, it’s an harsh comment about IoC, but I agree that by experience, there is a toll to pay to use that pattern and that price must be weighted with the benefits.

The benefits of IoC are obvious when you have a lot of components from different assemblies bound together.  With IoC, all the binding are bootstrapped in one place, in the IoC container.

Now if you have another strategy to loosely couple your components (e.g. services, layers, etc.), the benefit is less obvious because your components are then typically referring components in the same assembly.

Plus, let’s face it, an IoC-compliant component is annoying to use.  For instance, if we look at this component:

public class MyComponent
{
    public DbProviderFactory Provider { get; private set; }
    public DbConnection Connection { get; private set; }

    public void InvokeLogic()
    {
        //  Use Connection & Command
    }
}

When I instantiate MyComponent, it will throw a null-exception when I invoke InvokeLogic.  This is really annoying:  I need to construct everything to use that component.

You can circumvent that problem by passing dependency in the constructor.  This way you cannot instantiate a dysfunctional component.  But constructor-passed dependencies bring their lots of problem.  What if I want to mock only one sub-component?  I still have to construct all the dependencies.

Now, as I said, if there are benefits because your components are spread around the place and you want to minimize dependencies, the price is justified.  If all you want to do is to be able to mock some dependencies but in the normal (non test) scenarios you just want to instantiate components, keep reading!

In those scenarios, what I really want is:

  • Expose dependencies so a consumer can replace them
  • Have default implementation for those dependencies so a consumer can simply instantiate the component without setup-ing all its dependencies.
  • Have those default implementation lazy loaded because they might actually fail in my testing environment (e.g. they might look for a connection string in my config file and there are none).

Ok, it sounds like the solution will use the Lazy<T> class of .NET Framework.  Actually, a very simple solution to that is something in the lines of:

public class MyTestableComponent
{
    public Lazy<DbProviderFactory> Provider { get; set; }
    public Lazy<DbConnection> Connection { get; set; }

    public MyTestableComponent()
    {
        Provider = new Lazy<DbProviderFactory>(() => SqlClientFactory.Instance);
        Connection = new Lazy<DbConnection>(
            delegate
            {
                var conn = Provider.Value.CreateConnection();

                conn.ConnectionString = "Data Source=.;Initial Catalog=myDataBase;Integrated Security=SSPI;";

                return conn;
            });
    }

    public void InvokeLogic()
    {
        //  Use Connection & Command
    }
}

So what are we doing here?  We expose dependencies through properties.  But the properties are actually lazy evaluation of the real dependency.  So when you new your component, no dependencies are evaluated.

The default implementation of dependencies is done in the constructor.

Since Lazy<T> is using delegates and we are using closure (e.g. in the Connection property we fetch this.Provider from the surrounding context as opposed to a parameter passed to the delegate), we can even depend on other properties, as this consumer code demonstrate:

var comp = new MyTestableComponent();

Console.WriteLine(
    "{0} : \"{1}\"",
    comp.Connection.Value.ToString(),
    comp.Connection.Value.ConnectionString);
Console.WriteLine();

comp = new MyTestableComponent();
comp.Provider = new Lazy<DbProviderFactory>(() => OdbcFactory.Instance);

Console.WriteLine(
    "{0} : \"{1}\"",
    comp.Connection.Value.ToString(),
    comp.Connection.Value.ConnectionString);

This outputs

System.Data.SqlClient.SqlConnection : "Data Source=.;Initial Catalog=myDataBase;Integrated Security=SSPI;"

System.Data.Odbc.OdbcConnection : "Data Source=.;Initial Catalog=myDataBase;Integrated Security=SSPI;"

Hence we were able to change only the provider and the connection property still get initialized with the new provider and configured the same way.  Nice & simple.

If you do not like having Lazy<T> flying around, you’ll need to expose T properties with a private variable of type Lazy<T> and some method to override them.  I don’t mind exposing that I’m lazy Winking smile

The biggest problem with this approach is if you want to mock only one sub-sub-sub-sub component.  You then need to let the lazy load happened and then override that buried property.

This solution gives us mock-ability without the weight of IoC where it isn’t needed.

Ever used a similar solution?  Do you see any weaknesses?

Advertisements

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