2008-10-03 48 views
57

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

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

编辑:我想我应该澄清也许。我并不担心ConfigurationManager无法读取这些值,但我担心测试程序如何对读取的值做出反应。

回答

41

我通常会隔离外部依赖项,比如在他们自己的外观类中使用很少的功能读取配置文件。在测试中,我可以创建这个类的模拟版本,实现并使用它来代替实际的配置文件。你可以创建你自己的样机,或者使用像moq或rhino mocks这样的框架。

通过这种方式,您可以轻松地使用不同的配置值尝试您的代码,而无需编写首先编写xml配置文件的复杂测试。读取配置的代码通常很简单,只需要很少的测试。

0

其实,我想我应该做的是创建一个ConfigFileReader类用于我的项目,然后在单元测试工具中伪装它?

这是通常的事情吗?

16

可以同时读取和写入app.config文件与ConfigurationManager

+2

Ahhh,所以我可以在ConfigurationManager集合中设置值?我一直认为它是只读的。我想这就是我得到的假设:P – Dana 2008-10-03 21:14:32

+3

我刚刚尝试过,效果很好!例如,`ConfigurationManager.AppSettings [“SomeKey”] =“MockValue”;`。好答案! – 2011-07-29 18:51:54

+0

当我尝试它确实改变了密钥的值ü指定,但也删除值和所有其他键:( – Yasser 2014-09-18 06:19:21

1

您可以随时在包的接口读入位,并有从配置文件读取的具体实施。然后,您将使用模拟对象编写测试,以查看程序如何处理不良值。我个人并不会测试这个特定的实现,因为这是.NET Framework代码(我假设 - 希望 - MS已经测试过了)。

0

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

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

0

我有同样的问题,

你可以使用NUnit-console.exe C:\路径1 \ testdll1.dll C:\ PATH2 \ testdll2.dll

这工作得很好,即使如果两个DLL文件点不同app.configs 前testdll1.dll.config和testdll2.dll.config

,如果你想使用NUnit项目配置和包装这些两个DLL那么有没有办法可以有两个CONFIGS

你必须有project1。配置如果你的Nunit项目是project1.nunit与Project1.nunit位于同一位置。

希望这可以帮助

29

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

// 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 ... 

你当然可以设置你自己的帮手方法来更优雅地做到这一点。

11

我遇到了与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/

3

更优雅的解决方案是在配置设置本身上使用普通的旧依赖注入。恕我直言,这是比嘲笑配置阅读类/包装等更干净。

例如,说一个类“天气”需要一个“ServiceUrl”为了功能(例如说它调用Web服务来获取天气)。 Weather代码可以允许一些代码积极进入配置文件以获取该设置(无论该代码是否在Weather类中,或者是一个独立的配置读取器,可能会根据其他响应进行模拟),Weather类可以允许要注入的设置,可以通过参数传递给构造函数,也可以通过属性设置器注入。这样,单元测试非常简单直接,甚至不需要嘲笑。

然后可以使用Inversion of Control(或Dependency Injection)容器注入设置的值,因此Weather类的使用者不需要从某处显式提供值,因为它由容器处理。

2

为我工作:

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); 
    } 
20

您可以拨打ConfigurationManager.AppSettings来设置特定的单元测试所需的值的设定方法。

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

当单元测试运行,那么它会使用这些值来运行代码

0

好吧,我只是有同样的问题... 我想测试从引用的BL项目网站。 但我只想测试BL。因此,在测试项目的预生成事件中,我将app.Config文件复制到bin \ debug文件夹中,并从app.config中引用它们...