16

我一直在尝试使用文件流来模拟使用,但无法完成此操作并且不确定如何操作,我正在使用 rhino mock。

private Connection LoadConnectionDetailsFromDisk(string bodyFile)
{     
   //logic before
   using (FileStream fs = File.Open(bodyFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
   {
     return this.serverConfiguration.LoadConfiguration(fs, flowProcess);
   }
    //more logic
}

谁能告诉我如何模拟 using(FileStream....) 以便我能够访问代码的这个分支?

4

6 回答 6

13

您必须通过接口方法进行抽象File.Open(),然后才能模拟对它的调用。

所以

1)创建接口:

public interface IFileDataSource
{
   FileStream Open(string path,
                   FileMode mode,
                   FileAccess access,
                   FileShare share);
}

2) 更改LoadConnectionDetailsFromDisk()如下:

private Connection LoadConnectionDetailsFromDisk(string path, IFileDataSource fileSource)
{     
   using (FileStream fs = fileSource.Open(bodyFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
   {
      return this.serverConfiguration.LoadConfiguration(fs, flowProcess);
   }

   //more logic
}

3)在测试模拟接口并注入模拟

// create a mock instance
var sourceMock = MockRepository.GenerateMock<IFileDataSource>();

// setup expectation
sourceMock.Expect(m => m.Open("path", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
         .CallBack(
 delegate (string path, FileMode mode, FileAccess access, FileShare share)
 {
      // handle a call

     return true;
 }).Repeat.Any();

// TODO: depends on how you are triggering LoadConnectionDetailsFromDisk method call
// inject a mock

考虑到LoadConnectionDetailsFromDisk()您不能从测试中直接将模拟注入此方法调用,因此请说明如何调用此方法。

于 2012-06-21T15:23:10.110 回答
4

System.IO.Abstractions 项目NuGet 包还允许模拟FileStreams.

要使用它,您必须首先稍微更改获取 FileStream 的方式,例如:

private readonly IFileSystem _fileSystem; // this is from the third-party System.IO.Abstractions package

// This is assuming dependency injection to insert the mock file system during testing, 
// or the real one in production
public YourConstructor(IFileSystem fileSystem)
{
   _fileSystem = fileSystem;
}

private Connection LoadConnectionDetailsFromDisk(string bodyFile)
{     
   using (Stream fs = _fileSystem.FileStream.Create(bodyFile, FileMode.Open))
   {
       return this.serverConfiguration.LoadConfiguration(fs, flowProcess);
   }

   //more logic
}
于 2018-10-22T18:25:10.923 回答
1

您可以为此目的使用SystemWrapper库。它包含包装系统类的接口和类,并使您能够使用这些类对方法进行单元测试。

于 2015-07-24T07:59:14.940 回答
1

也许您可以使用下面的代码片段来模拟 FileStream

Mock<FileStream> mockFileStream = new Mock<FileStream>(new IntPtr(1), FileAccess.Read);

这样,您创建了一个新的 FileStream 实例,您可以像下面这样使用它

mockObject.Setup(s => s.GetFileStream(It.IsAny<string>())).Returns(mockFileStream.Object);

mockObject 是您返回 FileStream 的任何接口

于 2021-11-01T13:56:29.440 回答
0

我会重构该方法,以便将 FileStream 传递给该方法,以便您可以创建文件流的模拟

private Connection LoadConnectionDetailsFromDisk(FileStream bodyFile)
{ 
  ....
}

如果你真的想变得花哨,你总是可以接受一个 IStream 然后模拟那个 IStream 但 Rhino 支持创建 concreate 类的模拟

 MockRepository mocks = new MockRepository();
 FileStream basket = mocks.CreateMock<FileStream>();
于 2012-06-21T15:22:47.637 回答
0

我通过创建一个FileStream子类来处理它。基本构造函数确实要求我们打开一个实际文件,因此我包含一个设置为“内容”和“如果较新则包含”的简单文本文件,我们以只读和可共享的方式打开它。

然后我覆盖我实际需要的方法。就我而言,我需要 write 方法,并且我需要对写入的内容做一些事情,所以我注入了一个回调来调用。

private class CustomFileStream : FileStream
{
    private Action<string> WriteAction { get; }
    public CustomFileStream(Action<string> writeAction)
        // FileStream is notoriously hard to mock, so we inherit from it and we are a lightweight, real (but unused) FileStream underneath
        : base(Path.Combine(new ExecutionDirectory().Path /* Handle the execution directory in your own way */, "Content/DummyTextFile.txt"), FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
    {
        this.WriteAction = writeAction;
    }

    public override bool CanWrite => true;
    public override void Write(ReadOnlySpan<byte> buffer)
    {
        this.WriteAction(Encoding.UTF8.GetString(buffer));
    }
}
于 2019-09-10T14:29:01.997 回答