我扩展了一个访问硬盘上文件的旧库。我的单元测试项目中有嵌入资源这样的文件。
我已经移植了部分库以接受流,这允许我使用GetManifestResourceStream将我的嵌入式资源传递给旧库。这很好,但这是一个轻微的麻烦。维护这些图书馆的人不喜欢“混乱”或不得不发布新版本。
JustMock和TypeMock允许我拦截File.Open命令,我希望将库传递给FileStream对象,但是如何从Embedded Manifest Resource构造FileStream对象? 我当然可以创建一个物理文件,但我不想在运行测试时触摸文件系统。
答案 0 :(得分:2)
我根据您在此提到的要求烹制了样品。我在内存流中使用它,但也可以使用嵌入式资源。
byte[] actual = new byte[255];
// writing locally, can be done from resource manifest as well.
using (StreamWriter writer = new StreamWriter(new MemoryStream(actual)))
{
writer.WriteLine("Hello world");
writer.Flush();
}
// arrange the file system.
FileStream fs = (FileStream)FormatterServices
.GetSafeUninitializedObject(typeof(FileStream));
// mocking the specific call and setting up expectations.
Mock.Arrange(() => fs.Write(Arg.IsAny<byte[]>(), Arg.AnyInt, Arg.AnyInt))
.DoInstead((byte[] content, int offset, int len) =>
{
actual.CopyTo(content, offset);
});
// return custom filestream for File.Open.
Mock.Arrange(() => File.Open(Arg.AnyString, Arg.IsAny<FileMode>()))
.Returns(fs);
// act
var fileStream = File.Open("hello.txt", FileMode.Open);
byte[] fakeContent = new byte[actual.Length];
// original task
fileStream.Write(fakeContent, 0, actual.Length);
// assert
Assert.Equal(fakeContent.Length, actual.Length);
for (var i = 0; i < fakeContent.Length; i++)
{
Assert.Equal(fakeContent[i], actual[i]);
}
由于我正在调用mscorlib成员而FileStream.Write是一个实例调用/不包含在默认设置File,DateTime,FileInfo中。我还在TestInitailization期间添加了以下行。
Mock.Partial<FileStream>()
.For<byte[], int, int>((x, content, offset, len) =>
x.Write(content, offset, len));
[免责声明我为telerik工作]
希望有所帮助,
Mehfuz
答案 1 :(得分:1)
您可以阅读以下文章"Read embedded file from assembly"和"C#: Use Embedded Resource",其中演示了如何实现这一目标。
答案 2 :(得分:0)
您可以创建一个派生自FileStream
的新类,可能称为FauxFileStream
或其他东西,并覆盖其中所有必需的Stream
相关方法,以转而使用其他流。然后,您可以轻松地实例化new FauxFileStream(myManifestResourceStream)
并将其传递给库。
该课程看起来像这样:
class FauxFileStream : FileStream
{
private Stream _underlying;
public FauxFileStream(Stream underlying)
{
_underlying = underlying;
}
public override bool CanRead { get { return _underlying.CanRead; } }
public override bool CanSeek { get { return _underlying.CanSeek; } }
public override bool CanTimeout { get { return _underlying.CanTimeout; } }
public override bool CanWrite { get { return _underlying.CanWrite; } }
public override long Length { get { return _underlying.Length; } }
public override long Position { get { return _underlying.Position; } set { _underlying.Position = value; } }
public override int ReadTimeout { get { return _underlying.ReadTimeout; } set { _underlying.ReadTimeout = value; } }
public override int WriteTimeout { get { return _underlying.WriteTimeout; } set { _underlying.WriteTimeout = value; } }
public override void Close() { _underlying.Close(); }
public override void Flush() { _underlying.Flush(); }
public override int Read(byte[] buffer, int offset, int count) { return _underlying.Read(buffer, offset, count); }
public override int ReadByte() { return _underlying.ReadByte(); }
public override long Seek(long offset, SeekOrigin origin) { return _underlying.Seek(offset, origin); }
public override void SetLength(long value) { _underlying.SetLength(value); }
public override void Write(byte[] buffer, int offset, int count) { _underlying.Write(buffer, offset, count); }
public override void WriteByte(byte value) { _underlying.WriteByte(value); }
}
但是,目前这不会编译,因为你需要使用一些合理的参数调用FileStream
的基础构造函数。我能想到的最好的方法是传递打开一些文件进行读取的东西(这将是无害的,因为实际上不会读取文件,因为所有方法都被覆盖)。您可以为此创建一个0字节的文件,如果您将FileShare.Read
作为共享参数传递,则可以安全地打开同一个文件以便同时读取。