The art of dependency injection

Some time ago, I had some junior developers ask me why we should worry about dependency injection in our source code and what the value is. Well, the real value in my mind is being able to mock out other classes (dependencies) that our new object requires to be able to work. This can happen for a multitude of reasons. Two quick examples may be the following…

  • You have a data factory and want to pass the interface into the constructor of this class.
  • You want to verify the intended functionality of only that class.

Whatever that reason may be, we have DI to help with this. Below I will give an example of a class that uses constructor injector of the data access class followed by an advanced example that will also touch on the topic of interface mocking.

    public interface IDataLayer
    {
        string[] GetCustomerNames();
    }

    public class MyClass
    {
        private IDataLayer _dataLayer;

        public MyClass(IDataLayer dal)
        {
            _dataLayer = dal;
        }

        public char[] GetCustomerInitials()
        {
            var customers = _dataLayer.GetCustomerNames();
            return customers.Select(t => t[0]).ToArray();
        }
    }

As you can see above, this allows us to pass in the data access object that will be used as part of this class’ operation. Where we really start to see the benefit is through the use of interfaces and base classes.

Now in the next example, I have written a quick unit test to verify the expected outcome from our GetCustomerInitials method.  What you will see is the use of the MOQ mocking framework.  By using this framework, we are able to pass in an object that will return the values we supply when called. Thus we can test the logic of the method and verify that we get the expected value returned.

        [TestMethod()]
        public void GetCustomerInitialsTest()
        {
            string[] customers = {"John Doe", "Jane Doe", "Eric Smith"};
            var mock = new Mock<IDataLayer>(MockBehavior.Strict);
            mock.Setup(t => t.GetCustomerNames()).Returns(customers);

            IDataLayer dal = mock.Object;
            MyClass target = new MyClass(dal);
            
            char[] expected = {'J','J','E'};
            char[] actual = target.GetCustomerInitials();
            
            CollectionAssert.AreEqual(expected, actual);
        }

In some cases, I will factory up a data layer using a default constructor and then expose an additional constructor that is used specifically for unit testing. See the below example…

    public class MyClass
    {
        private IDataLayer _dataLayer;

        public MyClass()
        {
            _dataLayer = new DataAccess();
        }

        public MyClass(IDataLayer dal)
        {
            _dataLayer = dal;
        }

        public char[] GetCustomerInitials()
        {
            var customers = _dataLayer.GetCustomerNames();
            return customers.Select(t => t[0]).ToArray();
        }
    }

Based on the examples above, you can see how dependancy injection allows for our unit tests to be more direct and targeted to the method we want to test instead of any additional processing that it may be called during it’s execution.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s