ConfigurationManager.在单元测试项目中AppSettings返回Null
本文关键字:AppSettings 返回 Null 项目 单元测试 ConfigurationManager | 更新日期: 2023-09-27 18:09:33
我有一个c#单元测试项目,在app.config
文件中有应用程序设置。我正在测试存在于不同项目中的类。这个类同时依赖于ConfigurationManager.AppSettings
和ConfigurationManager.ConnectionStrings
。
被测试的类所在的项目没有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"];
考虑重构访问配置的代码以使用包装器。然后,您可以为包装器类编写mock,而不必为测试导入配置文件。
在两者共用的库中,设置如下:
public interface IConfigurationWrapper {
string GetValue(string key);
bool HasKey(string key);
}
然后,在需要访问config的库中,将该接口类型的实例注入到需要读取config的类中。
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();
那么在你的测试中,你就摆脱了依赖束缚。:)你可以创建一个实现iconfigationwrapper的假版本,并将其传递给你的测试,在那里你硬编码从GetValue
和HasKey
函数的返回值,或者如果你使用像Moq这样的模拟库:
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/
如果你使用的是。net Core,你的问题可能是一个已知的问题,因为测试进程运行为testhost.dll(或testhost.x86.dll),这意味着运行时配置文件预计将被命名为"testthost .dll.config";(或" testhostst .x86.dll.config"),而不是app.config输出(例如:"MyLibrary.Tests.dll.config")。
要修复它,请将下面的代码添加到您的项目文件(。csproj等)在根节点<Project>
内。在构建过程中,app.config的两个副本将放在输出目录中,并命名为"testhost.dll.config"answers"testhost.x86.dll.config",这将使您的应用程序设置再次工作。(您只需要其中一个文件,但包含两个文件会更安全。)
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
<Copy SourceFiles="app.config" DestinationFiles="$(OutDir)'testhost.dll.config" />
<Copy SourceFiles="app.config" DestinationFiles="$(OutDir)'testhost.x86.dll.config" />
</Target>
我建议app.config仅作为临时解决方案。如果你像我一样,你可能在升级。net框架项目到。net Core时遇到了这个问题,需要快速修复。但别忘了看看。net Core为存储应用设置提供的新的、更优雅的解决方案。
您提到了项目属性中的设置。看看你是否可以这样访问设置:
string test = Properties.Settings.Default.Bing_Key;
您可能需要获得项目设置文件定义位置的执行程序集,但请先尝试这个。
编辑
当使用Visual Studio的项目设置文件时,它会添加一些东西到你的app.config中,如果它不存在,它会创建app.config。ConfigurationManager不能触摸这些设置!您只能访问这些特定生成的项目。设置文件从使用上述静态方法。如果你想使用ConfigurationManager,你需要手工编写app.config。像这样添加你的设置:
<appSettings>
<add key="bing_api" value="whatever"/>
</appSettings>
然后他尖叫"NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"。
引用:我有一个c#单元测试项目与应用程序设置在app.config文件。我正在测试存在于不同项目中的类。该类依赖于两者,ConfigurationManager。AppSettings和ConfigurationManager.ConnectionStrings。
你不能这样做。永远! !为什么?因为您现在已经创建了一个依赖项。相反,应该使用依赖注入,这样类就可以完成它的工作,而不必查看属于应用程序的配置文件。