Friday, May 15, 2009

Setter injection - when its makes sense to use it

It is common enough to have a bunch of subclasses that all implement the same contract and have a common base class,dependencies, ctor etc.

Sometimes one of these subclasses needs an extra dependency. If you are working within a TTD framework, it is likely that you inject all dependencies into your classes via the ctor (i.e. ctor dependency injection). Now, because your new class breaks the mould, what do you do?

1. Do you update the base class to include this new dependency? - Bad as every other subclass does not require this dependency.

2. Do you create a subclass base class that contains this dependency. This isnt too bad but if you know that no other class will need this dependency then a subclass base class is wasteful.

3. Simply new up the dependency object in the subclass that requires it. This is ideal from a functional perspective. However we still cannot test the subclass as we cannot mock up the dependency.

4. Simply new up the dependency object in the subclass that requires it but in addition, add a setter method in the subclass to enable you to set the dependency with a mocked up dependency for testing purposes. In the actual code, the real dependency is still instantiated in the ctor. See the code extract below:


public class Class1: Base
{
private IExtraDependency c_extraDependency;

public IExtraDependency ExtraDependency
{
set { this.c_extraDependency= value; }
}

public Class1(Param1 p1) : base(p1)
{
this.c_extraDependency = new ConcreteExtraDependency();
}



The production code will never call the setter but the test code will. When using Castle Windsor or any other IOC container for that matter, I like to use constructor injection. However if an "oddball" dependency surfaces, that must be covered in testing - it doesnt make sense to always have to inject that dependency via ctor.

In the example above it makes sense to tightly bind Class1 with its extra dependency but we also make it testable via setter injection.

No comments:

Post a Comment