【问题标题】:Unit testing the app.config file with NUnit使用 NUnit 对 app.config 文件进行单元测试
【发布时间】:2010-09-15 04:45:56
【问题描述】:

当你们对依赖于 app.config 文件中的值的应用程序进行单元测试时?您如何测试这些值是否被正确读取以及您的程序如何对输入到配置文件中的错误值做出反应?

不得不修改 NUnit 应用程序的配置文件会很荒谬,但我无法从我想测试的 app.config 中读取值。

编辑:我想我应该澄清一下。我不担心 ConfigurationManager 无法读取值,但我关心的是测试我的程序如何对读取的值做出反应。

【问题讨论】:

    标签: .net unit-testing nunit


    【解决方案1】:

    我通常隔离外部依赖项,例如在他们自己的外观类中读取配置文件,功能很少。在测试中,我可以创建这个类的模拟版本,它实现并使用它而不是真正的配置文件。您可以为此创建自己的模型或使用 moq 或 rhino 模型等框架。

    这样您就可以轻松地尝试使用不同配置值的代码,而无需编写首先编写 xml 配置文件的复杂测试。读取配置的代码通常非常简单,几乎不需要测试。

    【讨论】:

    • 看到这个答案没有得到更多的支持,而其他关于添加/读取/编辑配置文件的答案有很多要点,这很可怕。对于读者来说,这个答案是保持单元测试简单可靠的方法。
    • "没有问题是再增加一层抽象解决不了的。" :-)
    • @lain "除了抽象层太多的问题" :)
    【解决方案2】:

    您可以在运行时在测试设置中修改配置部分。例如:

    // setup
    System.Configuration.Configuration config = 
         ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
    config.Sections.Add("sectionname", new ConfigSectionType());
    ConfigSectionType section = (ConfigSectionType)config.GetSection("sectionname");
    section.SomeProperty = "value_you_want_to_test_with";
    config.Save(ConfigurationSaveMode.Modified);
    ConfigurationManager.RefreshSection("sectionname");
    
    // carry out test ...
    

    您当然可以设置自己的辅助方法来更优雅地执行此操作。

    【讨论】:

    • 从磁盘读取文件会使整个测试套件变成集成测试。由于使用了全局状态和外部依赖项,因此您不再进行单元测试。
    【解决方案3】:

    您可以调用 ConfigurationManager.AppSettings 的 set 方法来设置该特定单元测试所需的值。

    [SetUp]
    public void SetUp()
    {
      ConfigurationManager.AppSettings.Set("SettingKey" , "SettingValue");
      // rest of unit test code follows
    }
    

    当单元测试运行时,它将使用这些值来运行代码

    【讨论】:

    • 对于我的目的来说,这是迄今为止最简单的解决方法。我的代码刚刚检查了名为 Environment 的键是 TEST 还是 LIVE。所以我只是在单元测试方法的开头将key设置为TEST。
    【解决方案4】:

    您可以使用ConfigurationManager 类读取和写入app.config 文件

    【讨论】:

    • 啊,所以我可以在 ConfigurationManager 集合中设置值?我一直认为它是只读的。我想这就是我做出假设的结果:P
    • 我刚试过这个,效果很好!例如,ConfigurationManager.AppSettings["SomeKey"] = "MockValue";。好答案!
    • 当我尝试时,它确实改变了你指定的键的值,但也删除了值和所有其他键:(
    • @Yasser:Mendelt 的解决方案更好;)
    • @StevenA.Lowe 我最终使用了红色 Pervez Choudhury 解决方案 :)
    【解决方案5】:

    我在使用 web.config....时遇到了类似的问题。我找到了一个有趣的解决方案。您可以封装配置读取功能,例如像这样:

    public class MyClass {
    
    public static Func<string, string> 
         GetConfigValue = s => ConfigurationManager.AppSettings[s];
    
    //...
    
    }
    

    然后正常使用

    string connectionString = MyClass.GetConfigValue("myConfigValue");
    

    但在单元测试中初始化“覆盖”这样的函数:

    MyClass.GetConfigValue = s =>  s == "myConfigValue" ? "Hi", "string.Empty";
    

    更多信息:

    http://rogeralsing.com/2009/05/07/the-simplest-form-of-configurable-dependency-injection/

    【讨论】:

      【解决方案6】:

      更优雅的解决方案是对配置设置本身使用普通的旧依赖注入。恕我直言,这比必须模拟配置读取类/包装器等更干净。

      例如,假设“天气”类需要“ServiceUrl”才能运行(例如,它调用 Web 服务来获取天气)。与其让某些代码行主动转到配置文件以获取该设置(无论该代码是在 Weather 类中还是可以根据其他一些响应模拟的单独配置读取器中),Weather 类可以允许要注入的设置,要么通过构造函数的参数,要么可能通过属性设置器。这样,单元测试就非常简单直接,甚至不需要 mocking。

      然后可以使用控制反转(或依赖注入)容器注入设置的值,因此 Weather 类的使用者不需要从某个地方显式提供值,因为它是由容器处理的。

      【讨论】:

        【解决方案7】:

        这对我有用:

         public static void BasicSetup()
          {
             ConnectionStringSettings connectionStringSettings = 
                  new ConnectionStringSettings();
             connectionStringSettings.Name = "testmasterconnection";
             connectionStringSettings.ConnectionString = 
                  "server=localhost;user=some;database=some;port=3306;";
             ConfigurationManager.ConnectionStrings.Clear();
             ConfigurationManager.ConnectionStrings.Add(connectionStringSettings);
          }
        

        【讨论】:

          【解决方案8】:

          您始终可以将读入位包装在接口中,并从配置文件中读取特定的实现。然后,您将使用 Mock Objects 编写测试,以查看程序如何处理错误值。 就个人而言,我不会测试这个特定的实现,因为这是 .NET Framework 代码(我假设 - 希望 - MS 已经对其进行了测试)。

          【讨论】:

            【解决方案9】:

            System.Configuration.Abstractions 在测试这类东西时是一件美妙的事情。

            这里是 GitHub 项目站点,其中包含一些很好的示例:enter link description here

            这里是 NuGet 站点:https://www.nuget.org/packages/System.Configuration.Abstractions/

            我在几乎所有的 .NET 项目中都使用它。

            【讨论】:

              【解决方案10】:

              实际上,进一步考虑,我想我应该做的是创建一个 ConfigFileReader 类以在我的项目中使用,然后在单元测试工具中伪造它?

              这是通常的做法吗?

              【讨论】:

                【解决方案11】:

                最简单的选择是包装读取配置的方法,以便您可以在测试期间替换值。创建一个用于读取配置的接口,并将该接口的实现作为构造函数参数传入或在对象上设置为属性(就像使用依赖注入/控制反转一样)。在生产环境中,传入一个真正从配置中读取的实现;在测试环境中,传入一个返回已知值的测试实现。

                如果您没有为可测试性重构代码的选项,但仍需要对其进行测试,Typemock Isolator 提供了实际模拟 .NET 框架配置类的能力,因此您可以说“下次我要求这样-and-such appSettings 值,返回这个已知值。”

                【讨论】:

                  【解决方案12】:

                  我遇到了同样的问题,

                  你可以使用 Nunit-console.exe c:\path1\testdll1.dll c:\path2\testdll2.dll

                  即使两个 dll 指向不同的 app.configs,这也能正常工作 ex testdll1.dll.config 和 testdll2.dll.config

                  如果您想使用 Nunit 项目配置并包装这两个 dll,那么您将无法拥有两个配置

                  如果您的 Nunit 项目是 project1.nunit,与 Project1.nunit 位于同一位置,则您必须拥有 project1.config。

                  希望对你有帮助

                  【讨论】:

                    【解决方案13】:

                    嗯,我也遇到了同样的问题... 我想测试一个从网站引用的 BL 项目。 但我只想测试 BL。因此,在测试项目的预构建事件中,我将 app.Config 文件复制到 bin\debug 文件夹中,并从 app.config 中引用它们...

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-02-20
                      • 2019-12-31
                      • 1970-01-01
                      • 2018-10-20
                      • 1970-01-01
                      • 1970-01-01
                      • 2017-04-04
                      相关资源
                      最近更新 更多