我处理这个问题的一种方法是创建一个文件系统的抽象,它只包含我需要的工具。在此示例中,我创建了一个实用程序来从 Git 日志历史记录中提取信息。我将所有方法都设为虚拟,以便可以模拟它们,但您也可以轻松定义接口。
/// <summary>
/// Class FileSystemService - an abstraction over file system services.
/// This class consists mainly of virtual methods and exists primarily to aid testability.
/// </summary>
public class FileSystemService
{
public virtual bool DirectoryExists(string path)
{
return Directory.Exists(path);
}
public virtual string PathCombine(string path1, string path2)
{
return Path.Combine(path1, path2);
}
public virtual string GetFullPath(string path)
{
return Path.GetFullPath(path);
}
public virtual void SaveImage(string path, Bitmap image, ImageFormat format)
{
image.Save(path, ImageFormat.Png);
}
}
创建文件系统服务后,将其注入任何需要它的对象,如下所示:
class SomeClassThatNeedsTheFileSystem
{
public SomeClassThatNeedsTheFileSystem(FileSystemService filesystem = null)
{
fileSystem = filesystem ?? new FileSystemService();
}
}
注意:这是一个相当小的项目,我不想参与 IoC 容器,所以我做了“穷人的 IoC”,将 FileSystemService 设为默认值为“null”的可选参数;然后,我在构造函数中测试 null 并新建一个 FileSystemService。理想情况下,对于更健壮的代码,我会将参数设置为强制参数并强制调用者传入 FileSystemService。
当需要创建一个假货时,我会这样做(我正在使用 MSpec 和 FakeItEasy):
// Some stuff elided for clarity
public class with_fake_filesystem_service
{
Establish context = () =>
{
Filesystem = A.Fake<FileSystemService>();
};
protected static FileSystemService Filesystem;
}