Trying to follow Buckminster Fuller's example in life, one step at a time to bring you brain scrapings for a new millennium.
How I Discovered A Love For Test Driven Development... Part 3
Dependencies are the set of assemblies/data/methods that a given application requires to run and the level of coupling to these assemblies/data/methods. In the normal tightly coupled pattern a user will hardcode any required dependencies at build time.
Dependency Injection removes coupling and allows dependencies to be resolved at runtime by injecting assemblies/data/methods into the application which satisfy a known requirement. This allows a programmer to change the behaviour of a program at runtime by controlling what is delivered at a given time.
What Has Any Of This To Do With TDD?
Welllll… Test Driven Development relies on reducing the surface under test so that any passes or failures give exact information about a given run. We may not care about all of the dependencies of a given class to test, so if possible they are replaced with mock objects which adhere to a known specification. By creating our own mock objects which always return some known state we can ensure that our tests are replicable and useful.
Dependency Injection allows us to inject mock objects at runtime which simplify the task of initialising any required state. Without doing so, many systems would be too complex and too tightly coupled to test.
An Example In C#...
As per our previous posts, to try out this example you need the following tools:
A C# compiler. Give Visual Studio Express a try which can be downloaded for free here.
The code below shows how to create a Constructor Injector which was one of the types of Dependency Injector suggested by Martin Fowler here. This example uses reflection to automate injection at the Assembly level which makes it a bit cleaner than other examples seen online.
To start, we need a way of marking classes which are injectable. This could be done by creating an interface, which would probably require extra implementation blocks to be added to derived classes. If the extra code overhead is too costly an attribute can be created to mark injectable classes with. In the example below the attribute is constructed with the interface or class that will be supported by a simple factory object.
In the example shown below a simple Assembly (TriangleAssembly) was created which contains the Triangle class marked by the SupportsAttribute. The Attribute informs us that the class should couple to the IShape interface.
Here is the simple IShape interface used in the code snippet above:
The code below outlines a simple Singleton Factory class which:
Reflects all of the marked injectable dependencies and adds them to a container if there is no constructor stored for a supportable type already.
Allows the construction of a supportable type if it has been previously reflected.
The very simple Program class below shows how an Assembly could be loaded at runtime, reflected to inject dependencies and a dependency constructed. There are a number of ways that the dependencies could be encoded, for example:
A wrapper class could explicitly load the dependencies by pulling Assemblies from known types, e.g. var assembly = typeof(TriangleAssembly.Triangle).Assembly;
An XML file containing the Assemblies to load could be parsed as part of the application initialisation step.
Any Assemblies in the same directory as the main application Assembly could be scanned for the SupportsAttribute.
This simple example should have given a basic outline for Constructor Dependency Injection using reflection.
A Test Driven Development blog post covering a few simple Dependency Injection and Mock frameworks... but before then expect to see C++11 shown some coder love.