如何同时模拟Directory.getFiles确保生产代码也能运行

时间:2019-07-03 08:13:13

标签: c# unit-testing system.io.file

如何同时模拟Directory.getFiles确保生产代码也能运行。例如,如果运行单元测试,它将运行模拟数据,如果在运行时生产中并且实际上已经传递了参数,则它将调用System.io.Directory。

2 个答案:

答案 0 :(得分:1)

我的建议是您使用System.IO.Abstractions,可从NuGet安装。然后,您将代码编码到接口IFileSystem,而不是直接编码到System.IO FileDirectory等对象。

因此,无论何时需要访问这些方法,都需要注入IFileSystem,这意味着必须向依赖注入控制器注册FileSystem的{​​{1}}实例,或者您需要将服务实例化为IFileSystem,那里有一个使用new MyService(new FileSystem())的构造函数参数。请注意,DI是执行此操作的首选方法。

让我们创建一个简单的服务,该服务返回当前目录中的文件:

IFileSystem

在这里您可以看到我们接受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()

嘿,请记住,它会打印出该项目的build文件夹的预期文件列表。

现在,我们如何测试它?为了这个示例,我使用xUnit和Moq。我的单元测试项目中也包含了// 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); } NuGet软件包。

首先,我们需要模拟System.IO.Abstractions对象:

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)); 方法中模拟的IFileSystem的实现,因此我们可以对其进行测试。请注意,如果您使用GetFileNames的不同重载,则需要模拟相关方法。

答案 1 :(得分:0)

您可以创建自己的包装器类,例如

    public interface IFileWrapper
    {
        FileInfo[] GetFiles(DirectoryInfo di);
    }

    public class FileWrapper : IFileWrapper
    {
        public FileInfo[] GetFiles(DirectoryInfo di)
        {
            return di.GetFiles();
        }
    }

然后您应该能够模拟出结果。

或者有一些可用的软件包,

希望有帮助