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

发布于 2024-09-18 22:43:57 字数 488 浏览 6 评论 0原文

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

在我的一些测试用例中,我想测试设置值的特殊组合,但我不知道如何更改单元测试代码中被测类看到的值。这些设置将始终从代码生成的类的属性中加载默认值。

在我的库类中,我访问如下设置:

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

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

I have a class library I want to unit test using Microsofts unit test framework. Some of the classes I want to test are configured using application settings. These settings are defined inside the Settings.settings file having application scope and suitable default values. When the library is used by the application these settings can be overriden in the App.Config file. If not the default values are used. That's exactly how I want it to be.

In some of my test cases I want to test special combinations of setting values but I don't know how to change the values seen by the class under test from the unit test code. These settings will always have their default value loaded from the attributes of the code generated class.

In my library class I access the settings like this:

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

How do I modify these settings in an unit test before the setting is accessed by the class under test? Making the internal settings class accessible by the unit test does not solve the problem as the settings have application scope and are read-only properties on the settings class.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

故事与诗 2024-09-25 22:43:57

在深入研究 ApplicationSettingsBase 和相关类之后,我想出了这个解决方案来解决我的问题。不是特别漂亮,但它确实能完成工作。

代码生成的设置类位于类库项目的内部,并且单元测试项目必须可以访问它。将 [ assembly:InternalsVisibleTo("UnitTestAssemblyName")] 属性添加到类库项目中的 AssemblyInfo.cs 中。

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

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

基础值现在存在并且可以在每个测试方法中设置。请记住使用正确的类型,因为代码生成的 getter 将进行强制转换:

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

After spelunking into the ApplicationSettingsBase and associated classes I've come up with this solution to my problem. Not particular beautiful, but it certainly gets the job done.

The code generated settings class is internal to the class library project and it has to be accessible to the unit test project. Add the [assembly: InternalsVisibleTo("UnitTestAssemblyName")] attribute to AssemblyInfo.cs in the class library project.

The settings are lazy loaded from the attributes on the settings class when a value is accessed. First step is to do a "dummy" read of a setting to force this lazy load. When unit testing you want to avoid settings values changed in one test to affect another hence it is necessary to "reset" the settings before lazy loading them. That can be done using the Reload() method. This code is placed in the test initialize method:

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

The underlying values now exist and can be set in each test method. Remember to use the correct type as the code generated getters will do a cast:

Settings.Default.PropertyValues["MyStringSetting1"].PropertyValue = "Foobar";
Settings.Default.PropertyValues["MyDoubleSetting2"].PropertyValue = 3.1416D;
天暗了我发光 2024-09-25 22:43:57

我将围绕 Settings 类创建一个包装器类,然后传递该包装器。然后您可以轻松模拟您的设置类。

我能想到的唯一的另一件事是稍微更轻量级且更容易模拟的选项,使您的设置文件实现一个反映所有设置的界面。对于调用者来说,这并没有太大的不同,但是在添加新设置时,您需要做的工作会减少。

两者都不是很棒,而且对于自动生成的代码来说必须这样做是很痛苦的,但据我所知,如果您真的想删除对设置文件的依赖,这似乎就是我们所坚持的。

例如,对于包含字符串应用程序设置和 int 用户设置的设置文件:

internal sealed partial class Settings : IMySettings {

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

internal interface IMySettings
{
    string ApplicationSetting
    {
        get;
    }

    string UserSetting
    {
        get;
        set;
    }
}

I'd create a wrapper class around the Settings class then pass that wrapper around. Then you can mock away your settings class with ease.

The only other thing I can come up with is the slightly more light-weight and easier to mock option of making your settings file implement an interface which reflects all your settings. It's not really much different for the caller, but you'll have less plumbing to do when adding new settings.

Neither is fantastic, and it is a pain to have to do it for auto-generated code, but it seems that's what we're stuck with as far as I can tell if you really want to remove the dependency on the settings file.

E.g. for a settings file containing a string Application setting and an int User setting:

internal sealed partial class Settings : IMySettings {

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

internal interface IMySettings
{
    string ApplicationSetting
    {
        get;
    }

    string UserSetting
    {
        get;
        set;
    }
}
余生一个溪 2024-09-25 22:43:57

所以你的设置可能会有所不同,但对我有用的是使用 Moq 来模拟 Microsoft.Extensions.Configuration.IConfiguration,如下所示:

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

So your setup may be different, but what worked for me was using Moq to mock the Microsoft.Extensions.Configuration.IConfiguration like this:

public void UnitTestName() {
//arrange
configMock = new Mock<IConfiguration>();
configMock.Setup(x => x.["keyName"]).Returns("value");
//assert
...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文