Interfaces, Testing and Dependency Injection in C#

Interfaces, Testing and Dependency Injection in C#

·

3 min read

Table of contents

No heading

No headings in the article.

When I first started out as developer, the usefulness of interfaces was one of the things I never quite worked out. However, as I got more into design and testing then everything suddenly became much more clear. By developing to interfaces we can make our applications much more extendable, easier to test, and making changes to the functionality much easier, simply by removing the dependency on a particular service.

Here I will demonstrate using interfaces to support testing through the use of dependency injection. To do this, I will use the principle of a simple logger. Imagine we have written an application with a logger that logs errors to a file system or database.

class Log
    {
        public void WriteMessage(string message)
        {
            // Write message out to database or file system
        }
    }

Now, if we have created a dependency on the logger itself we straight away hit two problems. Firstly, we may need the file path or database to be in place before we can run our application. Secondly, we cannot write a unit test for this application as a unit test should explicitly test the code, and not the integration with the file system/database. Further to this, we also cannot test the code is working without checking the output to see if something is written.

class DoWorkClassA
    {
        public void DoWorkClassA(Log log)
        {
            int a = 1;
            int b = 2;
            if (a != b)
            {
                log.WriteMessage("Value mismatch");
            }
        }
    }

The solution to this is to extrapolate an interface from our logger and use this as our dependency instead, as follows:

interface ILog
    {
        void WriteMessage(string message);
    }

We can then change our class objects to use the interface rather than the log object itself.

public void DoWorkClassA(ILog log)
        {
            int a = 1;
            int b = 2;
            if (a != b)
            {
                log.WriteMessage("Value mismatch");
            }
        }

Now if we write a unit test [or want to provide alternate logger implementations to make development easier], it’s as simple as providing a second implementation of the ILog interface and injecting this into our classes.

class LogForTesting : ILog
    {
        public void WriteMessage(string message)
        {
            Console.WriteLine(message);
        }
    }

Now, we can write a test, and inject our test log into the class we’re testing, so we can run the test without the need for the filesystem, the database or to use the ‘real’ log implementation that would be with the release version. In this example, also gives us the added benefit we can output what our log is doing to the console so can see in real-time what our application is logging.

\[TestFixture\]
    class Test
    {
        ILog log;
        \[TestFixtureSetUp\]
        public void SetUp()
        {
            this.log = new LogForTesting();
        }
        \[Test\]
        public void TestClassADoesWork()
        {
            DoWorkClassA classA = new DoWorkClassA(this.log);
            // Do test
        }
    }

The post Interfaces, Testing and Dependency Injection appeared first on Talking I.T. Through.

Did you find this article valuable?

Support Dave K by becoming a sponsor. Any amount is appreciated!