Tuesday, March 3, 2009 4:45 AM Kazi Manzur Rashid

Unit Testable Configuration Manager

If you are a TDD purist, you should know that accessing file system in Unit Test is violating the rule. But in our application, our infrastructural code often requires to access the configuration values form web.config/app.config. In this post, I will show you how can create a simple wrapper class which you can use in your unit tests without hitting the file system.

First, create a interface which will allow us to access the common sections of the configuration file:

public interface IConfigurationManager
{
    NameValueCollection AppSettings
    {
        get;
    }

    string ConnectionStrings(string name);

    T GetSection<T>(string sectionName);
}

Next, the implementation:

using System.Collections.Specialized;
using System.Configuration;

public class ConfigurationManagerWrapper : IConfigurationManager
{
    public NameValueCollection AppSettings
    {
        get
        {
            return ConfigurationManager.AppSettings;
        }
    }

    public string ConnectionStrings(string name)
    {
        return ConfigurationManager.ConnectionStrings[name].ConnectionString;
    }

    public T GetSection<T>(string sectionName)
    {
        return (T) ConfigurationManager.GetSection(sectionName);
    }
}

This is a very common pattern which you will find all over in the new ASP.NET 3.5 SP1 System.Web.Abstraction. The rule is whatever thing is not unit testable, create an interface with the exact same signature and create a wrapper class which internally calls the corresponding method/property.

Now lets say, we would like to do some processing with some configuration values like the following (By the way the Process() is a poor example):

public void Process()
{
    string appVersion = _configuration.AppSettings["version"];
    string connectionString = _configuration.ConnectionStrings("myDatabase");

    OutputCacheSettingsSection settings = _configuration.GetSection<OutputCacheSettingsSection>("system.web/caching/outputCacheSettings");
    int duration = 0;

    if (settings.OutputCacheProfiles.Count > 0)
    {
        OutputCacheProfile profile = settings.OutputCacheProfiles.Get("MyProfile");

        if (profile != null)
        {
            duration = profile.Duration;
        }
    }

    //Now perform operation with these values;
}

Now, we can write the unit test like the following which does not requires the web.config/app.config file:

[Fact]
public void Test_Process()
{
    _configuration.Expect(c => c.AppSettings).Returns(new NameValueCollection{ { "version", "1.0" } });
    _configuration.Expect(c => c.ConnectionStrings(It.IsAny<string>())).Returns(@"Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");

    OutputCacheProfile cacheProfile = new OutputCacheProfile("MyProfile") { Duration = 360 };
    OutputCacheSettingsSection cacheSection = new OutputCacheSettingsSection();
    cacheSection.OutputCacheProfiles.Add(cacheProfile);

    _configuration.Expect(c => c.GetSection<OutputCacheSettingsSection>(It.IsAny<string>())).Returns(cacheSection);

    _processor.Process();
}

Enjoy!!!

Download: UnitTestableConfiguration.zip

Shout it
Filed under: , , ,

Comments

No Comments