如何用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.configmyapp.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; } } }