2014-01-21 57 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,但有时遗留代码会阻碍它并使其太难为了安慰! –

相关问题