ASP. NET series: ConfigurationManager for unit testing,
When using the. NET configuration file through ConfigurationManager, you can add a configuration file to perform a unit test. Although you can pass the test, the decoupling is not achieved. It is better to use IConfigurationManager and ConfigurationManagerWrapper to adapt ConfigurationManager. ConfigurationManagerWrapper provides. NET configuration files. If you need to support other configurations, create different implementation classes for the IConfigurationManager interface.
1. Define the IConfigurationManager Interface
The Code originally dependent on ConfigurationManager is dependent on IConfigurationManager. Mock is convenient during unit testing.
public interface IConfigurationManager{ NameValueCollection AppSettings { get; } ConnectionStringSettingsCollection ConnectionStrings { get; } object GetSection(string sectionName);}
2. Create an adaptation class ConfigurationManagerWrapper
In non-unit test environments, ConfigurationManagerWrapper is used as the default Implementation of IConfigurationManager.
public class ConfigurationManagerWrapper : IConfigurationManager{ public NameValueCollection AppSettings { get { return ConfigurationManager.AppSettings; } } public ConnectionStringSettingsCollection ConnectionStrings { get { return ConfigurationManager.ConnectionStrings; } } public object GetSection(string sectionName) { return ConfigurationManager.GetSection(sectionName); }}
3. Custom generic configuration interface
When we need to use the configuration for our code, we can consider creating generic interfaces or using specialized strong interfaces. This example shows how to use a common interface.
public interface IConfiguration{ T Get<T>(string key, T @default);}
4. the. NET configuration file version that implements the configuration interface for generic Interfaces
AppConfigAdapter directly relies on the IConfigurationManager interface instead of using ConfigurationManager.
public class AppConfigAdapter : IConfiguration{ private IConfigurationManager _configurationManager; public AppConfigAdapter(IConfigurationManager configurationManager) { this._configurationManager = configurationManager; } public T Get<T>(string nodeName, T @default) { var value = this._configurationManager.AppSettings[nodeName]; return value == null ? @default : (T)Convert.ChangeType(value, typeof(T)); }}
5. Perform unit tests on the implementation of the generic configuration interface
Use the most popular unit testing framework and Mock Class Library: xUnit + Moq for unit testing.
public class AppConfigAdapterTest{ [Fact] public void GetStringTest() { var key = "key"; var value = "value"; var configuration = new AppConfigAdapter(this.GetConfigurationManager(o => o.Add(key, value.ToString()))); Assert.Equal(configuration.Get(key, string.Empty), value); } [Fact] public void GetIntTest() { var key = "key"; var value = 1; var configuration = new AppConfigAdapter(this.GetConfigurationManager(o => o.Add(key, value.ToString()))); Assert.Equal(configuration.Get(key, int.MinValue), value); } [Fact] public void GetBoolTest() { var key = "key"; var value = true; var configuration = new AppConfigAdapter(this.GetConfigurationManager(o => o.Add(key, value.ToString()))); Assert.Equal(configuration.Get(key, false), value); } [Fact] public void GetDateTimeTest() { var key = "key"; var value = DateTime.Parse(DateTime.Now.ToString()); var configuration = new AppConfigAdapter(this.GetConfigurationManager(o => o.Add(key, value.ToString()))); Assert.Equal(configuration.Get(key, DateTime.MinValue), value); } [Fact] public void GetDecimalTest() { var key = "key"; var value = 1.1m; var configuration = new AppConfigAdapter(this.GetConfigurationManager(o => o.Add(key, value.ToString()))); Assert.Equal(configuration.Get(key, decimal.MinValue), value); } private IConfigurationManager GetConfigurationManager(Action<NameValueCollection> set) { var appSettings = new NameValueCollection(); set(appSettings); var configurationManager = new Mock<IConfigurationManager>(); configurationManager.Setup(o => o.AppSettings).Returns(appSettings); return configurationManager.Object; }}
6. Summary
Convert the code that depends on the ConfigurationManager static class to the dependent IConfigurationManager interface, and inject the ConfigurationManagerWrapper implementation class at runtime. Use Mock to simulate an IConfigurationManager object during unit testing.