对于您的示例,我要做的第一件事是创建一个接口,公开您需要读取配置的功能,例如
public interface IConfigReader
{
string GetAppSetting(string key);
...
}
然后创建一个委托给静态 ConfigurationManager 类的实现:
public class StaticConfigReader : IConfigReader
{
public string Get(string key)
{
return ConfigurationManager.AppSetting[key];
}
}
然后对于依赖于配置的特定类,您可以创建一个接缝,该接缝最初只返回静态配置读取器的实例:
public class ClassRequiringConfig
{
public void MethodUsingConfig()
{
string setting = this.GetConfigReader().GetAppSetting("key");
}
protected virtual IConfigReader GetConfigReader()
{
return new StaticConfigReader();
}
}
并将所有对 ConfigManager 的引用替换为您的界面用法。然后出于测试目的,您可以子类化此类并覆盖 GetConfigReader 方法以注入假货,因此您不需要任何实际的配置文件:
public class TestClassRequiringConfig : ClassRequiringConfig
{
public IConfigReader ConfigReader { get; set; }
protected override IConfigReader GetConfigReader()
{
return this.ConfigReader;
}
}
[Test]
public void TestMethodUsingConfig()
{
ClassRequiringConfig sut = new TestClassRequiringConfig { ConfigReader = fakeConfigReader };
sut.MethodUsingConfig();
//Assertions
}
然后,当您添加 IoC 容器时,最终您将能够用属性/构造函数注入替换它。
编辑:如果您对将实例注入这样的单个类不满意(如果许多类依赖于配置,这将非常乏味),那么您可以创建一个静态配置类,然后允许对配置阅读器进行临时更改以进行测试:
public static class Configuration
{
private static Func<IConfigReader> _configReaderFunc = () => new StaticConfigReader;
public static Func<IConfigReader> GetConfiguration
{
get { return _configReaderFunc; }
}
public static IDisposable CreateConfigScope(IConfigReader reader)
{
return new ConfigReaderScope(() => reader);
}
private class ConfigReaderScope : IDisposable
{
private readonly Func<IConfigReader> _oldReaderFunc;
public ConfigReaderScope(Func<IConfigReader> newReaderFunc)
{
this._oldReaderFunc = _configReaderFunc;
_configReaderFunc = newReaderFunc;
}
public void Dispose()
{
_configReaderFunc = this._oldReaderFunc;
}
}
}
然后您的类只需通过静态类访问配置:
public void MethodUsingConfig()
{
string value = Configuration.GetConfigReader().GetAppSetting("key");
}
并且您的测试可以通过临时范围使用假货:
[Test]
public void TestMethodUsingConfig()
{
using(var scope = Configuration.CreateConfigScope(fakeReader))
{
new ClassUsingConfig().MethodUsingConfig();
//Assertions
}
}