如何使用moq模拟ConfigurationManager.AppSettings

Otu*_*uyh 115 c# unit-testing moq

我陷入了这个代码,我不知道如何模拟:

ConfigurationManager.AppSettings["User"];
Run Code Online (Sandbox Code Playgroud)

我必须模拟ConfigurationManager,但我没有线索,我正在使用Moq.

有人可以给我一个提示吗?谢谢!

Los*_*nos 155

我正在使用AspnetMvc4.刚才我写道

ConfigurationManager.AppSettings["mykey"] = "myvalue";
Run Code Online (Sandbox Code Playgroud)

在我的测试方法中,它工作得很好.

说明:测试方法在上下文中运行,应用程序设置取自,通常为web.configmyapp.config.ConfigurationsManager可以到达这个应用程序 - 全局对象并操纵它.

虽然:如果你有一个并行运行测试的测试运行器,这不是一个好主意.

  • 这是解决问题的巧妙而简单的方法!感谢简单! (7认同)
  • `ConfigurationManager.AppSettings`是一个`NameValueCollection`,它不是线程安全的,所以无论如何使用它而没有正确同步的并行测试都不是一个好主意.否则你只需在`TestInitialize`/ctor中调用`ConfigurationManager.AppSettings.Clear()`就可以了. (4认同)
  • 而已????当我为如何测试这个特殊的密封类而绞尽脑汁的时候,它的精巧之处就在于其简单性。 (2认同)

Jos*_*eld 102

我相信一种标准方法是使用外观模式来包装配置管理器,然后你可以控制松散耦合.

所以你将包装ConfigurationManager.就像是:

public class Configuration: IConfiguration
{
    public User
    {
        get{ 
               return ConfigurationManager.AppSettings["User"];
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

(您可以从配置类中提取接口,然后在代码中的任何位置使用该接口)然后您只需模拟IConfiguration.您可以通过几种不同的方式实现外观.上面我选择仅包装各个属性.您还可以获得使用强类型信息而不是弱类型哈希数组的附带好处.

  • 这在概念上也是我在做的事情.但是,我使用Castle DictionaryAdapter([Castle](http://www.castleproject.org)Core的一部分),它可以动态生成接口的实现.我前段时间写过这篇文章:http://blog.andreloker.de/post/2008/09/05/Getting-rid-of-strings-(3)-take-your-app-settings-to- the-next-level.aspx(向下滚动到"A Solution"以查看我如何使用Castle DictionaryAdapter) (6认同)
  • 显示如何做最小起订量的代码在哪里? (2认同)
  • 在上面,它只是将Moq用作“正常”。未经测试,但类似:`var configurationMock = new Mock <IConfiguration>();`,并用于设置:`configurationMock.SetupGet(s => s.User).Returns(“这是用户属性返回的内容!”) ;` (2认同)

Iri*_*dio 21

也许不是你需要完成的,但是你考虑过在你的测试项目中使用app.config吗?因此,ConfigurationManager将获取您在app.config中放置的值,而您无需模拟任何内容.这个解决方案适合我的需求,因为我从不需要测试"变量"配置文件.

  • 如果被测代码的行为根据配置值的值而改变,那么如果它不直接依赖于AppSettings,则测试它肯定更容易. (7认同)
  • 虽然其他人反对这个答案,但我会说他们的立场有点笼统.在某些情况下,这是一个非常有效的答案,它实际上只取决于您的需求.例如,假设我有4个不同的集群,每个集群都有不同的基本URL.这些4个集群在运行时从包含项目的"Web.config"中提取.在测试期间,从`app.config`中提取一些众所周知的值是非常有效的.单元测试只需要确保它拉动的条件说"cluster1"有效; 在这种情况下,只有4个不同的集群. (4认同)
  • 这是不好的做法,因为您从未测试过其他可能的设置.约书亚恩菲尔德的答案非常适合测试. (2认同)

Zor*_*ayr 14

您可以使用填充程序修改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.        
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在使用Microsoft Fakes隔离测试代码时阅读有关垫片和假货的更多信息.希望这可以帮助.

  • 作者要求如何使用moq,而不是MS Fakes. (6认同)
  • 这有什么不同?它通过从代码中删除数据依赖性来实现模拟.使用C#Fakes是一种方法! (6认同)

Dan*_*nNZ 8

你考虑过抄袭而不是嘲笑吗?该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...
    }
}
Run Code Online (Sandbox Code Playgroud)

优点是实现更简单,并且在您确实需要之前不依赖于System.Configuration.

  • 我最喜欢这种方法.一方面,使用Joshua Enfield建议的"IConfiguration"包装配置管理器可能会太高级别,并且您可能会错过由于配置错误解析等错误而导致的错误.另一方面,直接使用`ConfigurationManager.AppSettings`作为LosManos建议太多的实现细节,更不用说它可能对其他测试有副作用,不能在没有手动同步的并行测试运行中使用(如`NameValueConnection`不是线程安全的). (2认同)