Click here to Skip to main content
15,881,559 members
Articles / DevOps / Unit Testing

IConfigurationManager

Rate me:
Please Sign up or sign in to vote.
4.11/5 (2 votes)
26 Apr 2016CPOL2 min read 15.5K   2   4   3
How to test ConfigurationManager class by using interface instead of static class

Introduction

One thing that we should all do more is write unit tests. But sometimes, it is hard to write tests for your code. Recently, I was testing one method which used static class from .NET Framework and I didn’t know how to test it.

It was ConfigurationManager class.

In my earlier post, I talked about reading Web.config file using ConfigurationManager class. And today, I would like to show you how to improve this class even more, by using interface instead of static class.

And as a next step, how easy it is to test this interface.

Static Class

Imagine you are working on a project and you are asked to create class UrlCreator with one method.

C#
public string CreateUrlWithoutInterface(string[] parameters)
{
    StringBuilder sb = new StringBuilder();
    sb.Append(ConfigurationManager.AppSettings["baseurl"]);
    sb.Append("?");
    for (int i = 0; i < parameters.Length; i++)
    {
        sb.Append(string.Format("p{0}={1}", i+1, parameters[i]));
        if(i != parameters.Length - 1)
        {
            sb.Append("&");
        }
    }
    return sb.ToString();
}

This method uses ConfigurationManager on line 4. This method could be written better, but for the sake of this example, let's pretend it is a complicated method and you need to write the tests to verify the functionality.

However, when we want to test this method, we run into trouble.

C#
[TestMethod]
public void CreateUrl_noInterface()
{
    var creator = new UrlCreator(null);
    var parameters = new string[] { "a", "b", "c" };
    var result = creator.CreateUrlWithoutInterface(parameters);
    Assert.AreEqual("www.test.com?p1=a&p2=b&p3=c", result);
}

createremoved_nointerface

We are missing the baseurl path that is saved in a config file because there is no config file in Test project.

So how do we fix this? Well, we can use the interface and mock the method.

Interface

Same method but with using interface:

C#
public class UrlCreator
{
    IConfigurationManager _config;

    public UrlCreator(IConfigurationManager config)
    {
        _config = config;
    }

    public string CreateUrlWithInterface(string[] parameters)
    {
        StringBuilder sb = new StringBuilder();
        sb.Append(_config.GetAppSetting("baseurl"));
        sb.Append("?");
        for (int i = 0; i < parameters.Length; i++)
        {
            sb.Append(string.Format("p{0}={1}", i + 1, parameters[i]));
            if (i != parameters.Length - 1)
            {
                sb.Append("&");
            }
        }
        return sb.ToString();
    }
}

Here, we need to inject our IConfigurationManager into UrlCreator class. We can do this by simply using Dependency Injection Framework, or we can do it manually as I do it in the demo project.

In the method with the interface on line 4, we can see the change from static class ConfigurationManager to interface IConfigurationManager.

C#
[TestMethod]
public void CreateUrl_interface()
{
    var config = new FakeReader();
    var creator = new UrlCreator(config);
    var parameters = new string[] { "a", "b", "c" };
    var result = creator.CreateUrlWithInterface(parameters);
    Assert.AreEqual("www.test.com?p1=a&p2=b&p3=c", result);
}

1095807/createremoved_interface.png

The magic here is in the interface. You can create a custom implementation of the interface and therefore easily mock the interface. In the demo project, I am using the FakeReader class that returns predictable data for the test.

FakeReader

C#
public class FakeReader : IConfigurationManager
{
    public string GetAppSetting(string name)
    {
        return "www.test.com";
    }

    public string GetConnectionString(string name)
    {
        throw new NotImplementedException();
    }
}

Little side note here. You don’t have to create a separate class here in order to mock the method. You could easily use some mocking framework like Moq. But that is out of the scope of this article.

Summary

If you need to test a method that uses static class or method, try to decouple that static element into interface and than mock the interface instead. The functionality of the static method should be short and predictable, because you are also taking this piece of code out of unit testing. And in order to test this static method, you should use some kind of acceptance test.

You can download the whole project here.

This article was originally posted at http://codedreaming.com/iconfigurationmanager

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralA good step towards sorting out object configuration Pin
John Brett26-Apr-16 3:04
John Brett26-Apr-16 3:04 
GeneralRe: A good step towards sorting out object configuration Pin
xszaboj26-Apr-16 5:56
xszaboj26-Apr-16 5:56 
GeneralRe: A good step towards sorting out object configuration Pin
John Brett26-Apr-16 6:08
John Brett26-Apr-16 6:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.