代码之家  ›  专栏  ›  技术社区  ›  Tormod

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

  •  1
  • Tormod  · 技术社区  · 14 年前

    我扩展了一个访问硬盘上文件的遗留库。我在我的单元测试项目中有这样的文件作为嵌入式资源。

    我已经移植了部分库来接受流,这允许我使用GetManifestResourceStream将嵌入的资源传递给遗留库。这很好,但有点麻烦。维护这些库的人不喜欢“杂乱无章”或者不得不发布新版本。

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

    3 回复  |  直到 13 年前
        1
  •  2
  •   Mehfuz    14 年前

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

               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是一个实例调用/不包含在默认设置文件DateTime和FileInfo中。在测试期间,我还添加了以下行。

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

    [免责声明我为telerik工作]

    梅夫兹

        2
  •  1
  •   Community kfsone    7 年前

    你可以阅读以下文章 "Read embedded file from assembly" "C#: Use Embedded Resource" 这说明了如何实现这个目标。

        3
  •  0
  •   Timwi    14 年前

    您可以创建一个从 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); }
    }
    

    但是,目前这还不能编译,因为您需要调用 文件流 具有一些合理参数的s基构造函数。我能想到的最好方法是传递一些打开某个文件进行读取的内容(这将是无害的,因为文件实际上不会被读取,因为所有方法都被重写)。您可以为此目的创建一个0字节的文件,并且如果您通过了 FileShare.Read