2011-10-01 79 views
5

我在名为Tests.dll的程序集中为我的C#应用​​程序隔离了NUnit测试。关联的配置文件称为Tests.dll.config。这是Nunit使用的,而不是我的应用程序的实际配置文件。它看起来像这样(只显示几个配置选项有很多更多):为单元测试操作app.config文件

<?xml version="1.0" encoding="utf-8"?> 

<configuration> 
    <appSettings> 
    <add key="useHostsFile" value="true" /> 
    <add key="importFile" value="true" /> 

    </appSettings> 
</configuration> 

为了确保我的应用程序被彻底的测试,我需要改变测试之间的配置选项。 我运行了几个测试之后,我想向该文件添加一些新的配置值,并将它们用于后续测试。我需要添加什么代码才能做到这一点?

+0

您能更好地解释用例吗?为什么你需要在运行时更改tests.dll.config? –

+1

这是完全一样的问题,这一个:http://stackoverflow.com/questions/168931/unit-testing-the-app-config-file-with-ununit –

+0

好的,我想它可以被关闭。感谢指针。 – FunLovinCoder

回答

3

我推荐使用属性useHostsFile和importFile实现一个接口IConfig。然后我会删除所有直接依赖到这个文件,除了在实现IConfig的类ConfigDefault。在这个实现中你加载你的正常配置文件。对于每个测试,您可以实现另一个也从IConfig继承的类。我建议使用依赖注射。 Ninject是免费且易于使用的。

0

我用这个代码:

[TestMethod] 
    public void Test_general() 
    { 
     var cs = new ConnectionStringSettings(); 
     cs.Name = "ConnectionStrings.Oracle"; 
     cs.ConnectionString = "DATA SOURCE=xxx;PASSWORD=xxx;PERSIST SECURITY INFO=True;USER ID=xxx"; 
     cs.ProviderName = "Oracle.DataAccess.Client"; 

     var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); 
     //config.ConnectionStrings.ConnectionStrings.Clear(); 
     config.ConnectionStrings.ConnectionStrings.Remove(cs.Name); 
     config.ConnectionStrings.ConnectionStrings.Add(cs); 
     config.Save(ConfigurationSaveMode.Modified); 
     ConfigurationManager.RefreshSection("connectionStrings"); 

     // your code for your test here 
    } 
0

这里是我的两分钱这一挑战。简单地说,创建一个新的AppSettings类作为抽象层。在正常操作下,它只会从应用程序配置文件中读取设置。但是单元测试可以覆盖每个线程的设置,允许单元测试与不同的设置并行执行。

internal sealed class AppSettings 
{ 
    private static readonly AppSettings instance; 
    private static ConcurrentDictionary<int, AppSettings> threadInstances; 
    private string _setting1; 
    private string _setting2; 

    static AppSettings() { instance = new AppSettings(); } 

    internal AppSettings(string setting1 = null, string setting2 = null) { 
     _setting1 = setting1 != null ? setting1 : Properties.Settings.Default.Setting1; 
     _setting2 = setting2 != null ? setting2 : Properties.Settings.Default.Setting2; 
    } 

    internal static AppSettings Instance { 
     get { 
      if (threadInstances != null) { 
       AppSettings threadInstance; 
       if (threadedInstances.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadInstance)) { 
        return threadInstance; 
       } 
      } 
      return instance; 
     } 

     set { 
      if (threadInstances == null) { 
       lock (instance) { 
        if (threadInstances == null) { 
         int numProcs = Environment.ProcessorCount; 
         int concurrencyLevel = numProcs * 2; 
         threadInstances = new ConcurrentDictionary<int, AppSettings>(concurrencyLevel, 5); 
        } 
       } 
      } 

      if (value != null) { 
       threadInstances.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, value, (key, oldValue) => value); 
      } else { 
       AppSettings threadInstance; 
       threadInstances.TryRemove(Thread.CurrentThread.ManagedThreadId, out threadInstance); 
      } 
     } 
    } 

    internal static string Setting1 => Instance._setting1; 

    internal static string Setting2 => Instance._setting2; 
} 

在应用程序代码,用静态属性访问设置:

function void MyApplicationMethod() { 
    string setting1 = AppSettings.Setting1; 
    string setting2 = AppSettings.Setting2; 
} 

在单元测试中,任选地重写选定的设置:

[TestClass] 
public class MyUnitTest 
{ 
    [TestCleanup] 
    public void CleanupTest() 
    { 
     // 
     // Clear any app settings that were applied for the current test runner thread. 
     // 
     AppSettings.Instance = null; 
    } 

    [TestMethod] 
    public void MyUnitMethod() 
    { 
     AppSettings.Instance = new AppSettings(setting1: "New settings value for current thread"); 
     // Your test code goes here 
    } 
} 

注意:作为的AppSettings的所有方法类被声明为内部的,所以有必要使用以下属性使其对单元测试装配可见: [assembly:InternalsVisibleTo(“<程序集名称>,PublicKey = <公钥>“)]