2011-10-01 101 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 = <公鑰>「)]