您的位置:首页 > 编程语言 > ASP

ASP.NET 系列:单元测试之ConfigurationManager

2016-02-02 08:25 786 查看
通过ConfigurationManager使用.NET配置文件时,可以通过添加配置文件进行单元测试,虽然可以通过测试但达不到解耦的目的。使用IConfigurationManager和ConfigurationManagerWrapper对ConfigurationManager进行适配是更好的方式,ConfigurationManagerWrapper提供.NET配置文件方式的实现,如果需要支持其他配置,创建IConfigurationManager接口的不同的实现类即可。

1.定义IConfigurationManager接口

原本依赖ConfigurationManager的代码现在依赖IConfigurationManager。可以在单元测试时方便的Mock。

public interface IConfigurationManager
{
NameValueCollection AppSettings { get; }
ConnectionStringSettingsCollection ConnectionStrings { get; }
object GetSection(string sectionName);
}


2.创建适配类ConfigurationManagerWrapper

非单元测试环境使用ConfigurationManagerWrapper作为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.自定义泛型配置接口

在我们的代码需要使用配置时,可以考虑创建通用的泛型接口也可以使用专用的强类型的接口。这里演示使用通用的接口。

public interface IConfiguration
{
T Get<T>(string key, T @default);
}


4.实现泛型接口配置接口的.NET配置文件版本

AppConfigAdapter直接不使用ConfigurationManager而是依赖IConfigurationManager接口。

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.对泛型配置接口的实现进行单元测试

使用最流行的单元测试框架和Mock类库:xUnit+Moq进行单元测试。

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.总结

使依赖ConfigurationManager静态类的代码转换为依赖IConfigurationManager接口,运行时注入ConfigurationManagerWrapper实现类。单元测试时使用Mock模拟IConfigurationManager对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: