我如何模拟 Directory.GetFiles?

How do I mock Directory.GetFiles?

我正在尝试弄清楚如何或是否可以使用 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 变量,所以该方法使用模拟版本。这甚至是正确的方法吗?因为我不是在嘲笑 class,而是在嘲笑依赖项,所以我该如何设置文件变量,以便它查看模拟文件字符串 [].

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

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

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

您将以与注入 IFoo 完全相同的方式注入抽象。 现在您可以使用 Moq 模拟 IFileProvider,创建一个模拟 return 正是您想要它 return.

的字符串
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


还有一个变化。不是注入接口,而是注入委托:

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"} );