我的建议是您使用System.IO.Abstractions,可从 NuGet 安装。然后,您将代码编写到一个接口 IFileSystem,而不是直接编写到 System.IO File、Directory 等对象。
所以无论你在哪里需要访问这些方法,你都需要注入IFileSystem,这意味着FileSystem的实例,暴露为IFileSystem必须在你的依赖注入控制器中注册,或者你需要实例化你的服务为new MyService(new FileSystem()),其中有一个构造函数参数采用IFileSystem。请注意,DI 是执行此操作的首选方式。
让我们创建一个返回当前目录中文件的简单服务:
public class MyService
{
private readonly IFileSystem _fileSystem;
public MyService(IFileSystem fileSystem)
{
this._fileSystem = fileSystem;
}
public string[] GetFileNames()
{
return _fileSystem.Directory.GetFiles(_fileSystem.Directory.GetCurrentDirectory());
}
}
在这里你可以看到我们接受IFileSystem,它将被注入到我们的类中。我们的GetFileNames() 方法只是获取当前目录,获取其中的文件,然后返回它们。
现在让我们在生产代码中使用它:
// FileSystem should be registered with your dependency injection container,
// as should MyService. MyService should be resolved through the container
// and not manually instantiated as here.
var fileSystem = new FileSystem();
var service = new MyService(fileSystem);
var files = service.GetFileNames();
foreach (var file in files)
{
Console.WriteLine(file);
}
嘿,presto,它会打印出项目构建文件夹的预期文件列表。
现在,我们如何测试它?在本示例中,我使用的是 xUnit 和 Moq。我也在我的单元测试项目中包含了System.IO.Abstractions NuGet 包。
首先,我们需要模拟IFileSystem 对象:
var mockDirectory = new Mock<IDirectory>();
// set up the GetCurrentDirectory() method to return c:\
mockDirectory.Setup(g => g.GetCurrentDirectory()).Returns(@"c:\");
// Set up the GetFiles method to return c:\test.txt and c:\test2.txt where the path passed is c:\
mockDirectory.Setup(g => g.GetFiles(It.Is<string>(@"c:\"))).Returns(new[] { @"c:\test.txt", @"c:\test2.txt" });
var mockFileSystem = new Mock<IFileSystem>();
// Set up IFileSystem's .Directory property to return the mock of IDirectory that we created above
mockFileSystem.SetupGet(g => g.Directory).Returns(mockDirectory.Object);
// Create an instance of the mock that we can use in our service
var fileSystem = mockFileSystem.Object;
现在要对其进行测试,我们只需将其传递给服务并调用方法:
var myService = new MyService(fileSystem);
var files = myService.GetFileNames();
var expected = new[] { @"c:\test.txt", @"c:\test2.txt" };
Assert.True(files.SequenceEqual(expected));
这将在GetFileNames 方法中使用我们模拟的IFileSystem 实现,因此我们可以对其进行测试。请注意,如果您使用不同的 GetFiles 重载,则需要模拟相关方法。