我有一个用于日志记录的静态类:
public static class myLogger
{
public static ErrorLogging(string input)
{
//dostuff
}
}
我的使用方式是:
public class myClassthatDoesStuff
{
...
myLogger.ErrorLogging("some error ocurred");
...
}
如何对 myLogger 类进行最小化,以便能够对其进行单元测试并确保执行 ErrorLogging 方法? 是否可以在构造函数中不设置任何参数(构造函数注入(inject))的情况下执行此操作? myClassthatDoesStuff 要求构造函数中没有参数。
最佳答案
This blog post描述了完全相同的场景 - 您有一个旧的静态日志记录方法并希望在可测试代码中使用它。
将静态类包装在非静态类中 - 不仅用于测试,还用于一般用途。
将新的非静态类的方法提取到接口(interface)中。
无论您在何处依赖静态类,都应改为依赖接口(interface)。例如,如果类
DoesSomething
需要静态类中的函数,请执行以下操作:public interface ILogger { void ErrorLogging(string input); } public class MyClassthatDoesStuff { private readonly ILogger _logger; public MyClassthatDoesStuff(ILogger logger) { _logger = logger; } }
这有两个好处:
您可以对您的旧静态类进行单元测试(假设它没有状态并且不依赖于任何具有任何状态的东西)(尽管如果是这种情况我想您无论如何都可以对它进行单元测试。)
您可以对将使用该静态类的代码进行单元测试(通过删除对该静态类的直接依赖。)您可以将
ILogger
替换为模拟类,例如添加您的模拟类错误消息列表。class StringLogger : List<string>, ILogger { public void ErrorLogging(string input) { Add(input); } } var testSubject = new MyClassthatDoesStuff(new StringLogger());
一个更简单的选项不需要创建接口(interface)和适配器类。您可以创建一个 delegate
这就像一个方法的接口(interface)。
在记录器的情况下,它将是
delegate void Logging ErrorLoggingMethod(string input);
使用它看起来类似于使用界面:
public class MyClassthatDoesStuff
{
private readonly ErrorLoggingMethod _logger;
public MyClassthatDoesStuff(ILogger logger)
{
_logger = logger;
}
public void DoSomethingThatLogs()
{
// _logger is a method
_logger("Log something");
}
}
这更容易模拟和测试
string loggedMessage = null;
ErrorLoggingMethod fakeLogger = (input) => loggedMessage = input;
您可以将假记录器注入(inject)到您正在测试的类中。如果该类调用记录器,该方法会将记录的内容分配给变量。然后您可以断言已记录的任何内容,或仅断言已记录任何内容。
如果您的应用使用依赖项注入(inject)/IoC 容器,您可以像注册接口(interface)一样注册委托(delegate)。 Here's an example .
关于c# - 包装静态类/方法以便对其进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35827806/