在单元测试中修改应用程序设置

18

我有一个类库,想要使用微软的单元测试框架进行单元测试。其中一些我想要测试的类是使用应用程序设置进行配置的。这些设置在Settings.settings文件中定义,具有应用程序范围和适当的默认值。当应用程序使用该库时,这些设置可以在App.Config文件中被覆盖。如果没有,则使用默认值。这正是我想要的。

在我的某些测试用例中,我想要测试特定组合的设置值,但我不知道如何从单元测试代码中更改类所见到的值。这些设置始终会从代码生成类的属性中加载其默认值。

在我的类库类中,我通过以下方式访问设置:

var mySetting1 = Settings.Default.MySetting1;
var mySetting2 = Settings.Default.MySetting2;

在单元测试中,在类被测试之前如何修改这些设置?将内部设置类访问权限放开并不能解决问题,因为这些设置具有应用程序范围,并且是设置类上的只读属性。

3个回答

22

在深入研究ApplicationSettingsBase及其相关类之后,我得出了解决问题的方案。虽然不是非常优美,但它确实能够完成工作。

生成的代码设置类是内部的类库项目,必须对单元测试项目可见。在类库项目的AssemblyInfo.cs中添加[assembly: InternalsVisibleTo("UnitTestAssemblyName")]属性。

当访问值时,设置将从设置类的属性中惰性加载。第一步是进行一个“虚拟”读取设置以强制进行此惰性加载。在单元测试时,希望避免一个测试中更改的设置值影响另一个测试,因此有必要在惰性加载之前“重置”这些设置。这可以使用Reload()方法来完成。此代码放置在测试初始化方法中:

Settings.Default.Reload();
var dummy = Settings.Default.MySetting1;

现在这些底层值已经存在,可以在每个测试方法中进行设置。记得使用正确的类型,因为生成的getter代码将执行强制转换:

Settings.Default.PropertyValues["MyStringSetting1"].PropertyValue = "Foobar";
Settings.Default.PropertyValues["MyDoubleSetting2"].PropertyValue = 3.1416D;

谢谢,我自己永远不会想到解决这个问题。 - Aaron D

5
我会创建一个围绕Settings类的包装器类,然后传递该包装器类。这样,您可以轻松地模拟您的设置类。
我能想到的另一种选择是更轻量级且更易于模拟的选项,即使您的设置文件实现反映所有设置的接口。对于调用者来说,它并没有太大的区别,但是在添加新设置时,您需要做更少的管道工作。
两者都不是很好,而且为自动生成的代码做这些操作很麻烦,但是如果您真的想要消除对设置文件的依赖,那么据我所知,这就是我们被卡住的地方。
例如,对于包含字符串应用程序设置和整数用户设置的设置文件:
internal sealed partial class Settings : IMySettings {

    /*
     * here be auto-generate code (and dragons!)
     */
}

internal interface IMySettings
{
    string ApplicationSetting
    {
        get;
    }

    string UserSetting
    {
        get;
        set;
    }
}

我宁愿避免注入设置,因为我有很多库,并且随着我在依赖层次结构中向上移动,需要注入的依赖关系数量会大大增加。此外,包装由Visual Studio生成的类很繁琐。我希望有一种不是纯DI的解决方案,但可以很好地与.NET应用程序设置配合使用。 - Martin Liversage
很遗憾,我不认为有这样的一个解决方案。最好的可能是设置用户设置,但应用程序设置只能在文件外面改变。目前我唯一能想到的是使用接口,它比较轻量级,但仍然是纯DI,就像你说的那样。 - Dave D

0

所以你的设置可能不同,但对我有效的是使用Moq来模拟Microsoft.Extensions.Configuration.IConfiguration,像这样:

public void UnitTestName() {
//arrange
configMock = new Mock<IConfiguration>();
configMock.Setup(x => x.["keyName"]).Returns("value");
//assert
...
}

谢谢你的回答。然而,这个问题是在IConfiguration出现之前10多年就被提出来了。它涉及到基于App.Config的.NET Framework配置系统以及它与Visual Studio生成的设置的集成。 - Martin Liversage

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接