如何用moq模拟ConfigurationManager.AppSettings
我被困在这个我不知道如何模拟的代码中:
ConfigurationManager.AppSettings["User"];
我不得不嘲笑ConfigurationManager,但我没有线索,我正在使用Moq 。
有人可以给我一个小费? 谢谢!
我相信一个标准的方法是使用一个外观模式来包assembly置pipe理器,然后你有一些松散的耦合,你可以控制。
所以你会包装ConfigurationManager。 就像是:
public class Configuration: IConfiguration { public User { get{ return ConfigurationManager.AppSettings["User"]; } } }
(你可以从你的configuration类中提取一个接口,然后在代码中的任何地方使用这个接口)然后你只需要模拟IConfiguration。 您可以通过几种不同的方式来实现门面本身。 以上我select了包装各个属性。 您还可以获得强types信息而不是弱types哈希数组的副作用。
我正在使用AspnetMvc4。 刚才我写了
ConfigurationManager.AppSettings["mykey"] = "myvalue";
在我的testing方法,它完美的工作。
说明:testing方法在上下文中运行,取自通常为web.config
或myapp.config
应用程序设置。 ConfigurationsManager
可以访问这个应用程序全局对象并对其进行处理。
虽然:如果你有一个testing运行者并行运行testing,这不是一个好主意。
也许不是你需要完成的,但是你有没有考虑在你的testing项目中使用app.config? 所以ConfigurationManager会得到你放在app.config中的值,你不需要模拟任何东西。 这个解决scheme适合我的需求,因为我永远不需要testing一个“variables”configuration文件。
您可以使用垫片将AppSettings
修改为自定义的NameValueCollection
对象。 这里是一个如何实现这个目标的例子:
[TestMethod] public void TestSomething() { using(ShimsContext.Create()) { const string key = "key"; const string value = "value"; ShimConfigurationManager.AppSettingsGet = () => { NameValueCollection nameValueCollection = new NameValueCollection(); nameValueCollection.Add(key, value); return nameValueCollection; }; /// // Test code here. /// // Validation code goes here. } }
您可以阅读更多有关垫片和假货, 隔离与微软伪造testing代码 。 希望这可以帮助。
你有考虑过而不是嘲笑吗? AppSettings
属性是一个NameValueCollection
:
[TestClass] public class UnitTest1 { [TestMethod] public void TestMethod1() { // Arrange var settings = new NameValueCollection {{"User", "Otuyh"}}; var classUnderTest = new ClassUnderTest(settings); // Act classUnderTest.MethodUnderTest(); // Assert something... } } public class ClassUnderTest { private readonly NameValueCollection _settings; public ClassUnderTest(NameValueCollection settings) { _settings = settings; } public void MethodUnderTest() { // get the User from Settings string user = _settings["User"]; // log Trace.TraceInformation("User = \"{0}\"", user); // do something else... } }
好处是更简单的实现,并且不需要依赖于System.Configuration,除非你确实需要它。
这是一个静态属性,而Moq被devise为Moq实例方法或可以通过inheritance来模拟的类。 换句话说,莫克在这里不会对你有任何帮助。
为了模拟静态,我使用了一个名为Moles的工具,它是免费的。 还有其他的框架隔离工具,像Typemock也可以做到这一点,但我相信这些是付费工具。
当涉及到静态和testing时,另一个select是自己创build静态,虽然这往往是有问题的(因为,我想可能是你的情况)。
最后,如果隔离框架不是一个选项,而且你也承诺采用这种方法,那么Joshua提到的门面就是一个很好的方法,或者是一般的任何方法,你把这个客户端代码从业务逻辑中分离出来正在使用testing。
我认为写你自己的app.config提供者是一个简单的任务,并且比其他任何东西都更有用。 特别是你应该避免像垫片等假货,因为只要你使用它们,编辑&继续不再起作用。
我使用的提供者是这样的:
默认情况下,他们从App.config
获取值,但对于unit testing,我可以覆盖所有值,并在每个testing中独立使用它们。
不需要任何接口,也不需要每次都重复执行。 我有一个实用程序的DLL,并在许多项目和unit testing中使用这个小帮手。
public class AppConfigProvider { public AppConfigProvider() { ConnectionStrings = new ConnectionStringsProvider(); AppSettings = new AppSettingsProvider(); } public ConnectionStringsProvider ConnectionStrings { get; private set; } public AppSettingsProvider AppSettings { get; private set; } } public class ConnectionStringsProvider { private readonly Dictionary<string, string> _customValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); public string this[string key] { get { string customValue; if (_customValues.TryGetValue(key, out customValue)) { return customValue; } var connectionStringSettings = ConfigurationManager.ConnectionStrings[key]; return connectionStringSettings == null ? null : connectionStringSettings.ConnectionString; } } public Dictionary<string, string> CustomValues { get { return _customValues; } } } public class AppSettingsProvider { private readonly Dictionary<string, string> _customValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); public string this[string key] { get { string customValue; return _customValues.TryGetValue(key, out customValue) ? customValue : ConfigurationManager.AppSettings[key]; } } public Dictionary<string, string> CustomValues { get { return _customValues; } } }