对读取文件的静态函数进行单元测试
本文关键字:单元测试 静态函数 读取 文件 | 更新日期: 2023-09-27 18:13:35
我有以下功能,并试图在旧项目上添加单元测试。我是单元测试的初学者,所以如果问题很愚蠢,请原谅我…
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的部分。配置文件?
我尽量远离具有依赖性的静态实用程序,因为它们很难进行单元测试。但在这种情况下,这是可能的。你必须做一些重构。
首先需要抽象所有访问配置的调用。
public interface IThemeSettings {
bool Contains(string key);
string this[string key] { get; }
}
然后,您可以更新静态主题实用程序类,以使用此抽象作为依赖
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;
}
//...
}
现在,您可以配置该实用程序,以便在测试
时使用mock。[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作为mock框架。
一些建议。尽量不要让您的类与HttpContext
紧密耦合。你的类应该依赖于抽象而不是具体。
目前您的方法的设计方式不允许您模拟读取配置文件的部分。如果你想做到这一点你需要让它成为你方法的一个参数。一种简化的方法是定义像
这样的接口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);
}