最近,我一直在思考"模拟"从我试图测试的类中调用的静态方法的最佳方法.以下面的代码为例:
using (FileStream fStream = File.Create(@"C:\test.txt"))
{
string text = MyUtilities.GetFormattedText("hello world");
MyUtilities.WriteTextToFile(text, fStream);
}
Run Code Online (Sandbox Code Playgroud)
我知道这是一个相当糟糕的例子,但它有三个静态方法调用,它们略有不同.File.Create函数访问文件系统,我没有该函数.MyUtilities.GetFormattedText是我拥有的一个函数,它纯粹是无状态的.最后,MyUtilities.WriteTextToFile是我拥有的一个函数,它访问文件系统.
我最近一直在思考的是,如果这是遗留代码,我怎么能重构它以使它更可单元测试.我听过几个不应该使用静态函数的论点,因为它们很难测试.我不同意这个想法,因为静态函数是有用的,我不认为应该丢弃一个有用的工具只是因为正在使用的测试框架无法很好地处理它.
经过大量的搜索和审议,我得出的结论是,基本上可以使用4种模式或实践来使函数调用静态函数可单元测试.这些包括以下内容:
我听过很多关于前三种做法的讨论,但是当我在考虑这个问题的解决方案时,我想到了函数依赖注入的第四个想法.这类似于在接口后面隐藏静态函数,但实际上不需要创建接口和包装类.这方面的一个例子如下:
public class MyInstanceClass
{
private Action<string, FileStream> writeFunction = delegate { };
public MyInstanceClass(Action<string, FileStream> functionDependency)
{
writeFunction = functionDependency;
}
public void DoSomething2()
{
using (FileStream fStream = File.Create(@"C:\test.txt"))
{
string text = MyUtilities.GetFormattedText("hello world");
writeFunction(text, fStream);
}
}
}
Run Code Online (Sandbox Code Playgroud)
有时,为静态函数调用创建接口和包装类可能很麻烦,并且它可能会污染您的解决方案,其中许多小类的唯一目的是调用静态函数.我只是编写易于测试的代码,但这种做法似乎是一个糟糕的测试框架的解决方法.
当我考虑这些不同的解决方案时,我开始理解上面提到的所有4种做法都可以应用于不同的情况.以下是我认为应用上述实践的正确条件 …