c# - 我如何模拟 Directory.GetFiles?

标签 c# .net unit-testing moq

我正在尝试弄清楚如何或是否可以使用 Moq 执行以下操作

public class Download
{
    private IFoo ifoo;

    public Download(IFoo ifoo)
    {
        this.ifoo = ifoo;
    }

    public void Download()
    {
        var files = Directory.GetFiles("filepath"); //<<<===

        foreach (var item in files)
        {

            // do something

        }    
    }
}

在单元测试中。

// Arrange 

var mockFoo = new Mock<IFoo>();
mockFoo.setup( s => s.Bar()).returns(true);

var foo = new Foo(mockFoo.Object);

// Act
foo.Download()

如何模拟 files 变量,因此该方法使用模拟版本。这甚至是正确的方法吗?因为我不是在模拟类,而是在模拟依赖项,所以我该如何设置文件变量,以便它查看模拟文件字符串 []。

最佳答案

您需要依赖抽象来获取文件,而不是硬依赖 System.IO.Directory:

public interface IFileProvider
{
    string[] GetFiles(string path);
}

public class PhysicalFileProvider : IFileProvider
{
    public string[] GetFiles(string path)
    {
        return Directory.GetFiles(path);
    }
}

您将以与注入(inject) IFoo 完全相同的方式注入(inject)抽象。 现在您可以使用 Moq 模拟 IFileProvider,创建一个模拟来准确返回您希望它返回的字符串。

var fileProvider = new Mock<IFileProvider>();
fileProvider.Setup(x => x.GetFiles(It.IsAny<string>()))
    .Returns(new[] {"file1.txt", "file2.txt"});

您还可以使用 Microsoft.Extensions.FileProviders.Physical它提供文件系统访问和抽象。

public class Download
{
    private readonly IFoo _foo;
    private readonly Microsoft.Extensions.FileProviders.IFileProvider _fileProvider;

    public Download(IFoo foo, IFileProvider fileProvider)
    {
        _foo = foo;
        _fileProvider = fileProvider;
    }

    public void SomethingWithFiles()
    {
        var files = _fileProvider.GetDirectoryContents("filepath")
            .Where(item => !item.IsDirectory);

        foreach (var item in files)
        {
            // something
        }
    }
}

具体实现是PhysicalFileProvider


还有一个变化。不是注入(inject)接口(interface),而是注入(inject)委托(delegate):

public delegate string[] GetFilesFunction(string path);

public class Download
{
    private readonly IFoo _foo;
    private readonly GetFilesFunction _getFiles;

    public Download(IFoo foo, GetFilesFunction getFiles)
    {
        _foo = foo;
        _getFiles = getFiles;
    }

...

这更容易模拟。您甚至不需要最小起订量。

var subject = new Download(mockedFoo, path => new []{"file1.txt","file2.txt"} );

关于c# - 我如何模拟 Directory.GetFiles?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53620516/

相关文章:

c# - 与使用 winPcap 代替套接字相关的风险

c# - 用C#/NewtonSoft反序列化JSON时,能不能把一些结果展平?

.net - 如何在 vb - asp.net 中拆分带有多字符分隔符的字符串?

java - Powermock : Mocking static final logger

objective-c - Cocoa/Objective-C 中内存管理的单元测试

c++ - 如何创建需要汇总答案的单元测试?

c# - 自定义错误处理 ASP.NET

c# - 使用 FileSavePicker 在 Windows Phone 8.1 中保存图像

c# - 在 C# 多播委托(delegate)中使用多播

c# - .Net Standard 中 CompileToMethod 的替代方案