Dependency Injection Using Nested Classes
In my day job (lately it seems to be a 24 hour day) I do most of my work in C#, and all our new projects are implemented using Test Driven Development. Like most people doing TDD, we need to inject mock/stub/dummy objects into our objects under test. The traditional way to accomplish this is either via Constructor Injection or Setter Injection.
I have never been a fan of using setters to inject test objects, because it clutters the code with properties and methods that are only used for testing and are never used by production code. At first, I relied on constructor injection, but would sometimes run into cases where I was passing in half a dozen or more objects into the constructor. Many of these objects were simply helper classes that bundled up some functionality needed by the object under test only, and would never normally be used outside of that class.
Over the last year we have evolved another way of injecting mock objects into our test objects – Nested Class Injection (or as we call it, “TestHook Injection”). In C#, a nested class has access to it's containing class's private members, so we can use methods on the nested class to reach into the private details of the outer class. Here is a simple example:
public class ObjectUnderTest {
private IHelperObject _helper;
public ObjectUnderTest() {
_helper = new ProductionHelper();
}
public bool MethodToTest(int testNumber) {
return _helper.HelperMethod(testNumber);
}
public abstract class TestHook {
public static void InjectObjectHelper(ObjectUnderTest objectUnderTest, IHelperObject helper ) {
objectUnderTest._helper = helper;
}
}
}
Now all the test related code is contained within the abstract TestHook class. This class acts like the diagnostic connector on your car, allowing access to internal data and manufacturer's info without exposing it to the user. In fact, you can even use conditional compilation to exclude the TestHook class in the release build to remove the “connector” if code size or security is an issue.
Now when you are ready to test your objects, you can do something like:
[Test]
public void Test_MethodToTest() {
ObjectUnderTest objectUnderTest = new ObjectUnderTest();
IHelperObject mockHelperObject = new MockHelperObject();
ObjectUnderTest.TestHook.InjectObjectHelper(objectUnderTest, mockHelperObject);
objectUnderTest.MethodToTest(12);
// Test expectations here...
}
Note that I do not normally create my own mocks as shown above, I typically use Rhino Mocks to create mock objects, and Ninject as my IoC container. The contrived examples above are just to show the basic technique of using a nested class to cleanly access the internals of an object for testing purposes.
Now injecting objects like this is really only useful when those objects are only going to be used internally by the class under test. If you need to pass in an instance of an object that is shared between multiple objects, traditional constructor or setter injection is fine, since that is actually part of the object's contract with the world.
We have been using this technique for several months now, and it has resulted in cleaner production code, and more streamlined testing. Our test setup methods are simpler now, because we only need to inject mocks in the tests that need them instead of in the common test setup method.
I figured I should write this up since I have found the technique very useful, and a quick Google search didn't turn up anything useful. I expect this can be used in any language that supports nested classes where the nested class has access to the outer class's private member variables. Let me know in the comments if you find this technique helpful, or have any improvements. Thanks for stopping by!
0 comments:
Post a Comment