ConfigurationManager.AppSettings Returns Null In Unit Test Project

Jason Boyd picture Jason Boyd · Jun 19, 2014 · Viewed 24k times · Source

I have a C# unit test project with application settings in the app.config file. I am testing a class that exists in a different project. That class depends on both, ConfigurationManager.AppSettings and ConfigurationManager.ConnectionStrings.

The project that the class being tested resides in does not have an app.config file. I would have thought that because the class is being instantiated in the context of the unit test project that it would use the unit test project's app.config file. Indeed, that does seem to be the case for the connection string.

The class retrieves the connection string without any issues. However, when the class tries to retrieve any application settings the configuration manager always returns null. What is going on here?

Edit 1

I thought maybe it would be a good idea to try load some settings in the test project to see what happens. I tried to load the setting in the unit test immediately before calling the code that instantiates the class in the external project. Same result, nothing. I guess I can exclude the other project from the equation for the time being.

Here is an excerpt from my config file:

<configSections>
  <sectionGroup name="applicationSettings"
                type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
    <section name="MyNamespace.Properties.Settings"
             type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
             requirePermission="false" />
  </sectionGroup>
</configSections>

...

<applicationSettings>
  <MyNamespace.Properties.Settings>
    <setting name="Bing_Key"
             serializeAs="String">
      <value>...</value>
    </setting>
  </MyNamespace.Properties.Settings>
</applicationSettings>

and here is how I am attempting to load the setting:

string test = System.Configuration.ConfigurationManager.AppSettings["Bing_Key"];

Answer

xDaevax picture xDaevax · Jun 19, 2014

Consider refactoring your code that accesses the config to use a wrapper. Then you can write mocks for the wrapper class and not have to deal with the importing of the configuration file for the test.

In a library that is common to both, have something like this:

public interface IConfigurationWrapper {

    string GetValue(string key);
    bool HasKey(string key);
}

Then, in your libraries that need to access config, inject an instance of this interface type into the class that needs to read config.

public class MyClassOne {
    
    private IConfigurationWrapper _configWrapper;

    public MyClassOne(IConfigurationWrapper wrapper) {
        _configWrapper = wrapper;
    } // end constructor

    public void MethodThatDependsOnConfiguration() {
        string configValue = "";
        if(_configWrapper.HasKey("MySetting")) {
            configValue = _configWrapper.GetValue("MySetting");
        }
    } // end method

} // end class MyClassOne

Then, in one of your libraries, create an implementation that depends on the config file.

public class AppConfigWrapper : IConfigurationWrapper {
    
    public string GetValue(string key) {
        return ConfigurationManager.AppSettings[key];
    }

    public bool HasKey(string key) {
       return ConfigurationManager.AppSettings.AllKeys.Select((string x) => x.ToUpperInvariant()).Contains(key.ToUpperInvariant());
    }
}

Then, in the code that calls your class.

//Some method container
MyClassOne dataClass = new MyClassOne(new AppConfigWrapper());

dataClass.MethodThatDependsOnConfiguration();

Then in your test, you are free from dependency bondage. :) You can either create a fake version that implements IConfigurationWrapper and pass it in for your test, where you hard-code the return values from the GetValue and HasKey functions, or if you're using a mocking library like Moq:

Mock<IConfigurationWrapper> fakeWrapper = new Mock<IConfigurationWrapper>();

fakeWrapper.Setup((x) => x.GetValue(It.IsAny<string>)).Returns("We just bypassed config.");

MyClassOne testObject = new MyClassOne(fakeWrapper.Object);
testObject.MethodThatDependsOnConfiguration();

Here is an article that covers the concept (albeit, for web forms, but the concepts are the same): http://www.schwammysays.net/how-to-unit-test-code-that-uses-appsettings-from-web-config/