【问题标题】:How do I mock Directory.GetFiles?如何模拟 Directory.GetFiles?
【发布时间】:2018-12-04 19:56:45
【问题描述】:

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

【问题讨论】:

  • 与静态 Directory 紧密耦合。应该将其提取出来并封装在您控制的抽象后面
  • 好点,我可以使用短期解决方案吗?抽象将需要一些时间,因为这是一个简化的示例
  • 除非你能找到一个可以编织该调用的模拟库。我认为 TypeMock 可以,但我不确定它是否免费
  • 您可能还可以检查 Microsoft Fakes docs.microsoft.com/en-us/previous-versions/visualstudio/…
  • 看看这个:docs.microsoft.com/en-us/dotnet/api/…。这包含用于读取物理文件的类,还包含可以模拟的抽象。因此,与其依赖Directory.GetFiles("filepath"),不如依赖IFileProvider.GetDirectoryContents("path");

标签: c# .net unit-testing moq


【解决方案1】:

您需要依赖抽象来获取文件,而不是硬依赖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,创建一个可以准确返回您希望它返回的字符串的模拟。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-01
    • 2023-03-09
    • 1970-01-01
    • 2010-11-27
    • 1970-01-01
    • 2010-09-08
    相关资源
    最近更新 更多