July 23, 2010

Handling Many Dependencies in Unit Tests

We were recently talking about how to handle dependencies in unit tests, and someone mentioned that he used the IOC container to handle injecting the necessary dependencies for testing.  He preferred this approach because he had a lot of tests that each had a large number of dependencies, and most of them were the same for each test.  Each test, though, did have one or two dependencies that varied depending on the test.

Using an IOC container for unit testing seems a little heavy-handed to me, so I'd like to avoid it if possible—particularly if gross XML configuration files are involved.  I'd prefer to just directly insert the dependencies myself via constructor injection.  But having to create a large number of dependencies for each test quickly becomes onerous.  For times like these, I find my former coworker's approach quite simple and useful.

The idea is to create a dependencies object during test setup that creates default versions of all of the dependencies mutually used by several unit tests.  The tests can then reference this object when injecting dependencies.  And if a test needs a different or more customized dependency, it can just choose to ignore the default dependency created during setup.

Here's a quick example.  The Dependencies class and its instantiation with default dependencies in the test setup:

private class Dependencies
{
public Dependency Dependency { get; set; }
public Dependency2 AnotherDependency { get; set; }
public Dependency3 YetAnotherDependency { get; set; }
}

[SetUp]
public void Setup()
{
dependencies = new Dependencies
{
Dependency = new Dependency(),
AnotherDependency = new Dependency2(),
YetAnotherDependency = new Dependency3()
};
}

A test using these dependencies:

[Test]
public void test1()
{
// setup
var someClass = new SomeClass(dependencies.Dependency,
dependencies.AnotherDependency, dependencies.YetAnotherDependency);

// exercise
...

// verify
...
}

And a test that uses most of the default dependencies, but uses a different version of one of the dependencies that's tailored for this particular test:

[Test]
public void test2()
{
// setup
var yetAnotherDependency = new Dependency3 { SomeProperty = "test" };
var someClass = new SomeClass(dependencies.Dependency,
dependencies.AnotherDependency, yetAnotherDependency);

// exercise
...

// verify
...
}

Nothing mind-blowing here, but it's effective.  Of course, having classes with a large number of dependencies is probably a code smell, but if you nonetheless need to deal with a large number of dependencies when unit testing, applying the abovementioned approach can make your tests easier to implement and understand.

2 comments:

  1. For what it's worth, I've been experimenting with having something like this in the unit tests. I'm not sure yet what I think of it:

    public class SomeClassBuilder
    {
        private Dependency _dependency = new Dependency();
        private Dependency2 _anotherDependency = new Dependency2();
        private Dependency3 _yetAnotherDependency = new Dependency3();

        public SomeClassBuilder WithDependency(Dependency value)
        {
            _dependency = value;
            return this;
        }
        public SomeClassBuilder WithDependency2(Dependency2 value)
        {
            _anotherDependency = value;
            return this;
        }
        public SomeClassBuilder WithDependency3(Dependency3 value)
        {
            _yetAnotherDependency = value;
            return this;
        }

        public SomeClass Build()
        {
            return new SomeClass(_dependency, _anotherDependency, _yetAnotherDependency);
        }
    }

    ReplyDelete
  2. I've been trying out builders for entities that have a non-trivial amount of state to set and have thus far been happy with them.

    I like your suggestion and think I'll give it a shot. Thanks!

    ReplyDelete