嘲笑 File.OpenWrite()

Mocking File.OpenWrite()

我正在尝试编写一个单元测试,该测试写入一个用 File.OpenWrite() 打开的文件。

我正在使用 SystemWrapper 的 IFileWrap 接口包装文件。在生产中,我使用 SimpleInjector 注入 SystemWrapper 的 FileWrap class 的一个实例,并且工作正常。但我试图在我的单元测试中模拟 IFileWrap,使用最小起订量,但这不起作用。

我是 SystemWrapper 的新手,我正在尽最大努力了解它的用途。据我所知,IFileWrap.OpenWrite() returns 一个 IFileWrap 实例,您可以从中获取带有 FileStreamInstance 的流。

因此,在我的 class 测试中,我在构造函数中注入了一个 IFileWrap:

public class ClassUnderTest
{
    private readonly IFileWrap fileWrap;

    public ClassUnderTest(IFileWrap fileWrap)
    {
        this.fileWrap = fileWrap;
    }

    ...
}

在我的测试方法中,我从 FileStreamInstance 获取流:

var fsWrap = this.fileWrap.OpenWrite(fullPath);
var ostream = fswrap.FileStreamInstance;

这在生产中运行良好,其中 fileWrap 是使用 FileWrap 实例实例化的。但是在我的测试中,我正在尝试为 File.OpenWrite returns 模拟的 FileStream:

var fileStreamMock = new Mock<IFileStreamWrap>();

var fileMock = new Mock<IFileWrap>();
fileMock.Setup(fm => fm.OpenWrite(It.IsAny<string>())).Returns(fileStreamMock.Object);

var classUnderTest = new ClassUnderTest(fileMock.Object);

当我在调试器中遍历被测试的方法时,从我的单元测试中,fsWrap.FileStreamInstance 为 null,而我希望它是我的模拟文件流。

关于我做错了什么有什么想法吗?

您没有将 FileStreamInstance 存根到 return 任何东西,因此最小起订量将 return 为空。

创建 IFileStreamWrap mock 后,您需要为 FileStreamInstance 设置 return 一些东西:

var fileStreamWrapMock = new Mock<IFileStreamWrap>(); // Was fileStreamMock
var fileStreamMock = new Mock<FileStream>();
fileStreamWrapMock.Setup(fswm => fswm.FileStreamInstance).Returns(fileStreamMock);

最近我一直在为这个问题苦苦挣扎。正如您在 的评论中所建议的那样,我最初通过使用临时文件解决了它。我最近偶然发现了另一种方式,使用 StreamInstance 而不是 FileStreamInstance (当你提出问题时不确定这是否可用):

var outBuffer = new byte[512];
var fileWrap = new Mock<IFileWrap>();
var fileStreamWrap = new Mock<IFileStreamWrap>();
var stream = new Mock<IFileStreamWrap>();
fileStreamWrap.Setup(fsw => fsw.StreamInstance).Returns(new MemoryStream(outBuffer));

//I'm using File.Create to create temporary files with DeleteOnClose flag in the application, which get disposed before the function returns
fileWrap.Setup(fw => fw.Create(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<FileOptions>()))
    .Returns((string filepath, int i, FileOptions fo) =>
    {
        //I'm using filepath in a collection in my test to handle multiple files created in the application code
        return fileStreamWrap.Object;
    });


//Call application code that creates temporary file and closes eagerly with dispose.
//Application code will be something like:
var tempFileStream = _fileWrap.Create(tempFileName, 4096, FileOptions.DeleteOnClose);
using (var writer = new StreamWriter(tempFileStream.StreamInstance, Encoding.Default, 4096, true))
{...}


//Test file contents were written correctly into outBuffer
var outString = System.Text.Encoding.UTF8.GetString(outBuffer);
Assert.AreEqual("Important Business string", outString);