繁体   English   中英

对读取文件的静态函数进行单元测试

[英]unit test on a static function that read a file

我有以下功能,并尝试在一个旧项目上添加单元测试。 我是单元测试的初学者,如果问题很愚蠢,请原谅我...

public static string GetDefaultName(bool isResponsive)
    {
        //Read web.config file
        Configuration configuration = WebConfigurationManager.OpenWebConfiguration(System.Web.HttpContext.Current.Request.ApplicationPath);
        if (!isResponsive)
        {
            if (configuration.AppSettings.Settings.AllKeys.Contains("defaultTheme"))
            {
                return configuration.AppSettings.Settings["defaultTheme"].Value;
            }
            else
                return "default";
        }
        else
        {
            // ...
        }
    }

我正在尝试以这种方式编写单元测试:

 [TestMethod]
    public void ReturnDefaulThemeNametIfThemeIsResponsive()
    {
        var theme = new Theme {isResponsive = true};

        var defaultName = Themes.GetDefaultName(theme.isResponsive);
        Assert.AreEqual(defaultName, "defaultThemeResponsive");
    }

我想知道测试此静态功能的最佳方法是什么,以及如何模拟读取web.config文件的部分?

目前,您的方法设计方式不允许您模拟读取配置文件的部分。 如果您希望这样做,则需要将其设为方法的参数。 一种简化方法是定义一个接口,例如

public interface ISetting
{
    string GetConfigItem(string itemName);
}

然后将Configuration对象包装在实现此目的的设置管理器类中。

public class MySettings:ISetting
{
    public string GetConfigItem(string ItemName)
    {
        // return value of the setting. In your case code that gets value of "defaultTheme"
    }
}

您的方法现在将依赖ISetting

出于测试目的,您可以创建一个实现接口的模拟,并将返回所需的值,而与web.config的当前状态和内容无关

public class SettingsTestHelper:ISetting
{
    private _valueToReturn;
    public SettingsTestHelper(string valueToReturn)
    {
        _valueToReturn=valueToReturn;
    }
    public string GetConfigItem(string itemName)
    {
        return valueToReturn;
    }
}

有了这个,您现在可以创建一个单元测试(不编译,但是您会明白的)

[TestMethod]
public void CanGetSetting()
{
    var helper = new SettingsTestHelper("default");
    var result = ClasThatImplementsYourStaticMethod.GetDefaultName(helper, true);
    Assert.AreEqual(expected, actual);
}

我尝试远离具有依赖项的静态实用程序,因为它们很难进行单元测试。 但是在这种情况下是可能的。 您将必须进行一些重构。

首先,您需要抽象所有对访问配置的调用。

public interface IThemeSettings {
    bool Contains(string key);
    string this[string key] { get; }
}

然后,您可以更新静态Themes实用程序类,以将此抽象用作依赖项

public static class Themes {
    private static IThemeSettings themes;

    public static void Configure(Func<IThemeSettings> factory) {
        if (factory == null) throw new InvalidOperationException("Must provide a valid factory method");
        themes = factory();
    }

    public static string GetDefaultName(bool isResponsive) {
        if (themes == null) throw new InvalidOperationException("Themes has not been configured.");
        string result = string.Empty;
        if (!isResponsive) {
            if (themes.Contains("defaultTheme")) {
                result = themes["defaultTheme"];
            } else
                result = "default";
        } else {
            // ...
        }
        return result;
    }

    //...
}

那您现在可以将实用程序配置为在测试时使用模拟

[TestMethod]
public void ReturnDefaulThemeNametIfThemeIsResponsive() {
    //Arrange
    var key = "defaultTheme";
    var expected = "defaultThemeResponsive";

    var mockSettings = new Mock<IThemeSettings>();
    mockSettings.Setup(m => m.Contains(key)).Returns(true);
    mockSettings.Setup(m => m[key]).Returns(expected);

    //In production you would also do something like this with
    //the actual production implementation, not a mock
    Themes.Configure(() => mockSettings.Object);

    var theme = new Theme { isResponsive = true };

    //Act
    var defaultName = Themes.GetDefaultName(theme.isResponsive);

    //Assert
    Assert.AreEqual(expected, defaultName);
}

在这种情况下,我使用Moq作为模拟框架。

一些忠告。 尽量不要让您的类与HttpContext紧密耦合。 您的类应依赖抽象而不是依赖。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM