2014-01-21 92 views
2

我正在使用MSTest來測試應用程序。該測試需要某些特定的值,通常不會出現在應用程序配置文件中。如何在測試環境中替換配置文件?

所以我需要在測試運行時替換一個知名的包含值的配置文件,以便System.Configuration.ConfigurationManager指向正確的文件。 (即我僞造真正的配置文件,通過替換我以前做的另一個)

我可以做所有的事,除了當我的測試執行時,System.Configuration.ConfigurationManager已經讀取配置文件,所以新值被忽略。

示例代碼:

static TemporaryConfigFile config; 
    [ClassInitialize] 
    public static void ClassInitialise(TestContext testContext) 
    { 
     string sourceResource = "Intra_Matrix_Scheduler_Tests.Resources.test.config"; 
     string tempConfigFileName = "test.config"; 
     config = TemporaryConfigFile.CreateFromEmbeddedResource(Assembly.GetExecutingAssembly(), sourceResource, tempConfigFileName); 
    } 

    [ClassCleanup] 
    public static void ClassCleanUp() 
    { 
     config.Dispose(); 
    } 

(上述代碼創建與已知的測試值的新的配置文件,並且在點它AppDomain.CurrentDomain(「APP_CONFIG_FILE」)在生產代碼重新路由到的這種技術。另一個配置文件完美的作品,如果在應用程序的開始)完成

的問題是,下面的生產線,當被測試行使,不檢索所需的測試值:

 var dict = (System.Collections.Specialized.NameValueCollection)System.Configuration.ConfigurationManager.GetSection("ScheduledTasks"); 

原因很明顯,儘管生產代碼行和測試代碼現在指向正確的配置文件,但生產配置文件已被加載到內存中,因此測試配置文件被有效忽略。

所以問題是:如何強制System.Configuration.ConfigurationManager重新讀取配置文件,或者如何配置文件被僞造?另外,如何在測試期間直接修改內存中的配置文件? (據我所知,我不能使用依賴注入和MOQ嘲笑它,因爲System.Configuration.ConfigurationManager是靜態的)

TIA

回答

0

我建議你從其他真正的類隔離測試類(比如ConfigurationManager)和尤其是在與環境(文件,網絡,數據庫等)隔離的情況下,因爲您的測試可能由於某些與您正在測試的代碼無關的外部原因而失敗(文件可能不存在,數據庫連接錯誤等)。這很容易做到,如果你要創建自己的非靜態配置管理器,這將委派所有工作ConfigurationManager

public class ConfigurationManagerWrapper : IConfigurationProvider 
{ 
    public NameValueCollection GetScheduledTasksSettings() 
    { 
     return (NameValueCollection)ConfigurationManager 
        .GetSection("ScheduledTasks"); 
    } 
} 

然後讓你的SUT(被測類)取決於ICoolConfigurationProvider抽象這是很容易嘲笑(也考慮返回一些更具體的業務不是名稱,收藏價值):

public interface IConfigurationProvider 
{ 
    NameValueCollection GetScheduledTasksSettings(); 
} 

與SUT的樣子:

public class SUT 
{ 
    private IConfigurationProvider _configProvider; 

    public SUT(IConfigurationProvider configProvider) 
    { 
     _configProvider = configProvider; 
    } 

    public void Exercise() 
    { 
     var dict = _configProvider.GetScheduledTasksSettings(); 
     // ... 
    } 
} 

現在你可以很容易地爲你的測試提供任何數值:

[TestMethod] 
public void ShouldDoSomething() 
{  
    var configMock = new Mock<IConfigurationProvider>(); 

    configMock.Setup(c => c.GetScheduledTasksSettings()) 
      .Returns(new NameValueCollection {{ "foo", "bar" }}); 

    var sut = new SUT(configMock.Object); // inject configuration provider 
    sut.Exercise(); 

    // Assertions 
} 
+1

謝謝,我在我回到這個線程之前,偶然發現了同樣的東西。很高興知道我在正確的軌道上。 –

+0

@NeilHaughton welcome :)單元測試也應該很快 - 這是使用mocks代替讀取文件或製作數據庫查詢的另一個原因 –

+0

我儘可能地使用mock,但有時遺留代碼會阻礙它並使其太難爲了安慰! –

相關問題