Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

IConfigurationManager

0.00/5 (No votes)
26 Apr 2016 1  
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.

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.

[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:

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.

[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

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here