如何将解决方案资源作为 FileStream 对象传递(到拦截的 File.Open 命令)?

发布于 2024-09-14 04:46:54 字数 286 浏览 3 评论 0原文

我扩展了一个访问硬盘上文件的旧库。我的单元测试项目中有嵌入资源等文件。

我已经移植了库的部分内容以接受流,这允许我使用 GetManifestResourceStream 将嵌入的资源传递到旧库。这工作得很好,但有点麻烦。维护这些库的人不喜欢这种“混乱”或必须发布新版本。

JustMock 和 TypeMock 允许我拦截 File.Open 命令,并且我希望向库传递 FileStream 对象,但如何从嵌入式清单资源构造 FileStream 对象? 我当然可以创建一个物理文件,但我不希望在运行测试时触及文件系统。

I extend upon a legacy library which accesses files on the harddrive. I have such files as embedded resources in my unit test project.

I have ported parts of the library to accept streams, which allows me to use GetManifestResourceStream to pass my embedded resource to the legacy library. This works fine, but it is a slight hassle. And people maintaining those libraries don't appreciate the "clutter" or having to publish new releases.

JustMock and TypeMock allows me to intercept the File.Open commmand, and I wish to pass the library a FileStream object, but how do I construct a FileStream Object from an Embedded Manifest Resource?
I could of course create a physical file, but I don't wish to touch the file system while running tests.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

旧时光的容颜 2024-09-21 04:46:54

我根据你在这里提到的要求做了一个样品。我在内存流中使用它,但也可以使用嵌入式资源来完成。

           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 是一个实例调用/不包含在默认设置文件、日期时间、文件信息中。我还在 TestInitailization 期间添加了以下行。

           Mock.Partial<FileStream>()
              .For<byte[], int, int>((x, content, offset, len) => 
            x.Write(content, offset, len));

[我为 Telerik 工作的免责声明]

希望有帮助,

Mehfuz

I have cooked a sample based on the requirments you mentioned here. I used in memory stream for it but can done with embedded resource as well.

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

Since i am moking a mscorlib member and FileStream.Write is a instance call / not contains in the default set File, DateTime, FileInfo. I also added the following line during TestInitailization.

           Mock.Partial<FileStream>()
              .For<byte[], int, int>((x, content, offset, len) => 
            x.Write(content, offset, len));

[Disclaimer i work for telerik]

Hope that helps,

Mehfuz

梦一生花开无言 2024-09-21 04:46:54

您可以阅读以下文章“从程序集中读取嵌入式文件”"C#: Use Embedded Resource" 演示了如何实现这个目标。

You could read the following articles "Read embedded file from assembly" and "C#: Use Embedded Resource" which demonstrates how to achieve this goal.

滥情稳全场 2024-09-21 04:46:54

您可以创建一个从 FileStream 派生的新类,可能称为 FauxFileStream 或其他名称,并重写其中所有必要的与 Stream 相关的方法改为不同的流。然后,您可以轻松实例化一个新的 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 作为共享参数传递,则可以安全地打开同一文件以同时读取。

You could create a new class deriving from FileStream, perhaps called FauxFileStream or something, and override all the necessary Stream-related methods in it to go to a different stream instead. Then you can easily instantiate a new FauxFileStream(myManifestResourceStream) and pass that to the library.

The class would look something like this:

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

However, at the moment this doesn’t compile because you need to call the FileStream’s base constructor with some reasonable arguments. The best I could think of is to pass something that opens some file for reading (which will be harmless because the file will not actually be read because all the methods are overridden). You could create a 0-byte file for this purpose and you can safely open the same file for reading simultaneously if you pass FileShare.Read as the share parameter.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文