Shapejam

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

26 Jun 2013 - Nic Ho Chee

In previous posts we have concentrated on creating our first unit test. Today we'll look at a simple Dependency Injection example in C# and why this allows us to create better testable code.

What Is Dependency Injection?

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:

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.

using System;

namespace ShapeInterfaces
{
    /// <summary>
    /// Our attribute which marks the type which we will support in our factory classes.
    /// </summary>
    [System.AttributeUsage(System.AttributeTargets.Class)]
    public class SupportsAttribute : System.Attribute
    {
        private System.Type m_type;

        /// <summary>
        /// Simple constructor that takes the type we're going to support in our factory.
        /// </summary>
        public SupportsAttribute(System.Type type)
        {
            if (type == null)
                throw new ArgumentException("Supports attribute called with null object.");

            m_type = type;
        }

        /// <summary>
        /// Give us the supported type we're expecting to construct in a factory.
        /// </summary>
        public System.Type Supported
        {
            get
            {
                return (m_type);
            }
        }
    }
}

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.

using System;
using ShapeInterfaces;

namespace TriangleAssembly
{
    /// <summary>
    /// A simple Triangle class which will be injected into our factory.
    /// </summary>
    [Supports(typeof(IShape))]
    public class Triangle : IShape
    {
        /// <summary>
        /// Get the current number of sides of our triangle.
        /// </summary>
        public int SideCount
        {
            get
            {
                return (3);
            }
        }
    }
}

Here is the simple IShape interface used in the code snippet above:

using System;

namespace ShapeInterfaces
{
    /// <summary>
    /// Interface exposing simple shape information.
    /// </summary>
    public interface IShape
    {
        // Simple property that gets the number of sides for the shape.
        int SideCount
        {
            get;
        }
    }
}

The code below outlines a simple Singleton Factory class which:

using System;
using System.Reflection;
using System.Collections.Generic;
using ShapeInterfaces;

namespace DependencyInjection
{
    /// <summary>
    /// A simple factory singleton to pull out types marked with the SupportAttribute and store a 
    /// default constructor for later construction.
    /// </summary>
    public sealed class Factory
    {
        /// <summary>
        /// Singleton instance of our factory.
        /// </summary>
        private static volatile Factory s_instance;

        /// <summary>
        /// Lock to ensure factory is threadsafe.
        /// </summary>
        private static Object s_lock = new Object();

        /// <summary>
        /// A complete dictionary of products that this factory can create.
        /// </summary>
        private IDictionary<Type, ConstructorInfo> m_products = new Dictionary<Type, ConstructorInfo>();

        /// <summary>
        /// Private constructor to ensure singleton access.
        /// </summary>
        private Factory()
        {
        }

        /// <summary>
        /// Static singleton accessor.
        /// </summary>
        public static Factory Instance
        {
            get
            {
                if (s_instance == null)
                {
                    lock (s_lock)
                    {
                        // Only need to lock if we have no factory yet...
                        if (s_instance == null)
                            s_instance = new Factory();
                    }
                }

                return ( s_instance );
            }
        }

        /// <summary>
        /// Attempt to load all supportable types from the assembly.
        /// </summary>
        public void LoadTypes(Assembly assembly)
        {
            if (assembly == null)
                throw new ArgumentException("Attempting to load a type from a null assembly");

            foreach (Type type in assembly.GetTypes())
            {
                // We're only interested in types that support our SupportsAttribute class...
                foreach (Object attribute in type.GetCustomAttributes(typeof(SupportsAttribute), true))
                {
                    // We're only interested in non-static public constructors, for the moment with no parameters. 
                    foreach (ConstructorInfo constructor in type.GetConstructors(BindingFlags.Public | BindingFlags.Instance))
                    {
                        lock (s_lock)
                        {
                            if (constructor.GetParameters().Length == 0 &amp;&amp; !m_products.ContainsKey(((SupportsAttribute)attribute).Supported))
                            {
                                m_products.Add(((SupportsAttribute)attribute).Supported, constructor);
                                break;
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Create an object of the required type or return null if we don't support it.
        /// </summary>
        public Object Create(Type type)
        {
            if (m_products.ContainsKey(type))
                return (m_products[type].Invoke(new Object[0]));

            return (null);
        }
    }
}

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:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading.Tasks;
using ShapeInterfaces;

namespace DependencyInjection
{
    class Program
    {
        static void Main(string[] args)
        {
            // Load the assembly from a qualified name to show that we can load from a string name.
            Assembly assembly = Assembly.LoadFrom("TriangleAssembly.dll");
            
            // Get the assembly from the fully qualified name...
            Factory.Instance.LoadTypes(assembly);

            // Create a shape object from the constructor that supports the shape interface.
            IShape shape = Factory.Instance.Create(typeof(IShape)) as IShape;

            Console.WriteLine("The object which supports IShape has " + shape.SideCount + " sides");
        }
    }
}

This simple example should have given a basic outline for Constructor Dependency Injection using reflection.

Next...

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.