ConfigurationManager.在单元测试项目中AppSettings返回Null

本文关键字:AppSettings 返回 Null 项目 单元测试 ConfigurationManager | 更新日期: 2023-09-27 18:09:33

我有一个c#单元测试项目,在app.config文件中有应用程序设置。我正在测试存在于不同项目中的类。这个类同时依赖于ConfigurationManager.AppSettingsConfigurationManager.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"];

ConfigurationManager.在单元测试项目中AppSettings返回Null

考虑重构访问配置的代码以使用包装器。然后,您可以为包装器类编写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的假版本,并将其传递给你的测试,在那里你硬编码从GetValueHasKey函数的返回值,或者如果你使用像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。

你不能这样做。永远! !为什么?因为您现在已经创建了一个依赖项。相反,应该使用依赖注入,这样类就可以完成它的工作,而不必查看属于应用程序的配置文件。