15

我有一个C#单元测试项目,其中的应用程序设置位于app.config文件中。我正在测试一个存在于不同项目中的类。该班级取决于两个,ConfigurationManager.AppSettingsConfigurationManager.ConnectionStringsConfigurationManager.AppSettings返回空单元测试项目

被测试的类所驻留的项目没有app.config文件。我会想,因为这个类正在单元测试项目的上下文中被实例化,所以它会使用单元测试项目的app.config文件。事实上,连接字符串似乎确实如此。

该类检索连接字符串没有任何问题。但是,当班级尝试检索任何应用程序设置时,配置管理器始终会返回null。这里发生了什么?

编辑1

我想,也许这将是一个好主意,尝试在测试项目,看看会发生什么加载某些设置。我试图在调用实例化外部项目中的类的代码之前立即在单元测试中加载设置。同样的结果,没有。我想我可以暂时排除等式中的其他项目。

这里是我的配置文件的摘录:

<configSections> 
    <sectionGroup name="applicationSettings" 
       type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > 
    <section name="MyNamespace.Properties.Settings" 
      type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
      requirePermission="false" /> 
    </sectionGroup> 
</configSections> 

... 

<applicationSettings> 
    <MyNamespace.Properties.Settings> 
    <setting name="Bing_Key" 
      serializeAs="String"> 
     <value>...</value> 
    </setting> 
    </MyNamespace.Properties.Settings> 
</applicationSettings> 

,这里是我如何我尝试加载设置:

string test = System.Configuration.ConfigurationManager.AppSettings["Bing_Key"]; 
+2

你检查的App.config文件的生成动作需要的内容和复制到输出目录设置需要“如果更新,则复制”。 –

+0

这些东西都没有按照你描述的那样设置。改变它们并不能解决问题。 –

+0

在你的'app.config'中,config部分的类型和命名空间是否与CM.AppSettings命名空间相匹配? – mxmissile

回答

4

你提到的项目属性设置。看看你是否可以访问该设置是这样的:

string test = Properties.Settings.Default.Bing_Key; 

您可能需要获取的项目设置文件被定义成执行的程序集,但先试试这个。

编辑

当使用Visual Studio的项目设置文件,它增加了东西到你的app.config并创建的app.config如果它不存在。 ConfigurationManager不能触摸这些设置!您只能使用上述静态方法来获取这些特定的生成的project.settings文件。如果你想使用ConfigurationManager,你需要手写你的app.config。像这样添加你的设置:

<appSettings> 
    <add key="bing_api" value="whatever"/> 
</appSettings> 
+0

这是在单元测试项目中的作品。但是,正在测试的外部项目中没有Properties.Settings类。 –

+0

纠正我,如果我错了,但它听起来像你需要这个外部项目能够挂钩到你的项目设置,无论他们可能碰巧住在哪里。如果是这样的话,这可能会有助于跨不同的程序集访问该设置文件:http://stackoverflow.com/questions/2548476/accessing-another-projects-settings-file –

+0

纠正我,如果我错了(我可能是),但我认为app.config文件有点像加载到主应用程序(本例中为单元测试项目)的线程中的全局/环境容器。然后,在读取任何配置属性时,任何其他dll(在这种情况下的测试系统)将读取来自同一全局配置容器的属性。 –

10

考虑重构你的代码,访问配置使用包装。然后你可以为包装类写mock,而不必处理为测试导入配置文件。

在这是常见的两种库,有这样的事情:

public interface IConfigurationWrapper { 

    string GetValue(string key); 
    bool HasKey(string key); 
} 

然后,在你的图书馆需要访问配置,注入该接口类型的实例为需要阅读类配置。

public class MyClassOne { 

    private IConfigurationWrapper _configWrapper; 

    public MyClassOne(IConfigurationWrapper wrapper) { 
     _configWrapper = wrapper; 
    } // end constructor 

    public void MethodThatDependsOnConfiguration() { 
     string configValue = ""; 
     if(_configWrapper.HasKey("MySetting")) { 
      configValue = _configWrapper.GetValue("MySetting"); 
     } 
    } // end method 

} // end class MyClassOne 

然后,在其中一个库中,创建一个依赖于配置文件的实现。

public class AppConfigWrapper : IConfigurationWrapper { 

    public string GetValue(string key) { 
     return ConfigurationManager.AppSettings(key); 
    } 

    public bool HasKey(string key) { 
     return ConfigurationManager.AppSettings.AllKeys.Select((string x) => x.ToUpperInvariant()).Contains(key.ToUpperInvariant()); 
    } 
} 

然后,在调用你的类的代码中。

//Some method container 
MyClassOne dataClass = new MyClassOne(new AppConfigWrapper()); 

dataClass.MethodThatDependsOnConfiguration(); 

然后在您的测试中,您不受依赖关系的束缚。 :)您可以创建一个实现IConfigurationWrapper仿版,并通过它在你的测试,你硬编码从GetValueHasKey功能,或者如果你使用像起订量嘲弄库的返回值:

Mock<IConfigurationWrapper> fakeWrapper = new Mock<IConfigurationWrapper>(); 

fakeWrapper.Setup((x) => x.GetValue(It.IsAny<string>)).Returns("We just bypassed config."); 

MyClassOne testObject = new MyClassOne(fakeWrapper.Object); 
testObject.MethodThatDependsOnConfiguration(); 

这里是覆盖概念的文章(虽然,对于Web表单,但其概念是相同的):http://www.schwammysays.net/how-to-unit-test-code-that-uses-appsettings-from-web-config/

相关问题