单元测试添加到 Zip/从 Zip 中提取

发布于 2024-07-25 23:20:06 字数 1467 浏览 9 评论 0原文

我有以下用于添加到 Zip 或从 Zip 中提取的代码。 我正在尝试重构它以使其做好测试准备。 有人可以指导我如何实现这一目标吗? 旁白:我使用 Moq 作为我的模拟框架,使用 MSTest 作为我的单元测试工具,

private const long BufferSize = 4096;

public static void ExtractZip(string zipFilename, string folder) {
  using (var zip = System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate)) {
    foreach (var part in zip.GetParts()) {
      using (var reader = new StreamReader(part.GetStream(FileMode.Open, FileAccess.Read))) {
        using (var writer = new FileStream(folder + "\\" + Path.GetFileName(part.Uri.OriginalString),
                                           FileMode.Create, FileAccess.Write)) {
          var buffer = System.Text.Encoding.UTF8.GetBytes(reader.ReadToEnd());
          writer.Write(buffer, 0, buffer.Length);
        }
      }
    }
  }
}

public static void AddFileToZip(string zipFilename, string fileToAdd) {
  using (var zip = System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate)) {
    var destFilename = ".\\" + Path.GetFileName(fileToAdd);
    var uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
    if (zip.PartExists(uri)) {
      zip.DeletePart(uri);
    }
    var part = zip.CreatePart(uri, "", CompressionOption.Normal);
    using (var fileStream = new FileStream(fileToAdd, FileMode.Open, FileAccess.Read)) {
      using (var dest = part.GetStream()) {
        CopyStream(fileStream, dest);
      }
    }
  }
}

提前致谢。

I have the following code for adding to/extracting from Zip. I'm trying to refactor this to make it test-ready. Can someone provide pointers on how I can accomplish this?
Aside: I'm using Moq as my mock framework and MSTest as my Unit Testing tool

private const long BufferSize = 4096;

public static void ExtractZip(string zipFilename, string folder) {
  using (var zip = System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate)) {
    foreach (var part in zip.GetParts()) {
      using (var reader = new StreamReader(part.GetStream(FileMode.Open, FileAccess.Read))) {
        using (var writer = new FileStream(folder + "\\" + Path.GetFileName(part.Uri.OriginalString),
                                           FileMode.Create, FileAccess.Write)) {
          var buffer = System.Text.Encoding.UTF8.GetBytes(reader.ReadToEnd());
          writer.Write(buffer, 0, buffer.Length);
        }
      }
    }
  }
}

public static void AddFileToZip(string zipFilename, string fileToAdd) {
  using (var zip = System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate)) {
    var destFilename = ".\\" + Path.GetFileName(fileToAdd);
    var uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
    if (zip.PartExists(uri)) {
      zip.DeletePart(uri);
    }
    var part = zip.CreatePart(uri, "", CompressionOption.Normal);
    using (var fileStream = new FileStream(fileToAdd, FileMode.Open, FileAccess.Read)) {
      using (var dest = part.GetStream()) {
        CopyStream(fileStream, dest);
      }
    }
  }
}

Thanks in advance.

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

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

发布评论

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

评论(3

一袭白衣梦中忆 2024-08-01 23:20:06

我将使这两个静态方法(ExtractZip 和 AddFileToZip)成为实例方法,并将其放入接口中:

public interface IZipper
{
  void ExtractZip(string zipFilename, string folder);
  void AddFileToZip(string zipFilename, string fileToAdd);
}

public class Zipper : IZipper
{
  public void ExtractZip(string zipFilename, string folder)
  { 
    //...
  }

  void AddFileToZip(string zipFilename, string fileToAdd)
  {
    //...
  }
}


// client code
class Foo
{
  private IZipper myZipper;
  // gets an instance of the zipper (injection), but implements only 
  // against the interface. Allows mocks on the IZipper interface.
  public Foo(IZipper zipper)
  {
    myZipper = zipper;
  }

}

客户端代码现在很容易测试。

Zipper 类怎么样?

  • 考虑一下是否值得进行测试。
  • 在我们的项目中,我们区分单元测试(隔离)和集成测试,其中可以使用数据库或文件系统。 您可以将其声明为“文件系统集成测试”。 当然,只允许使用测试目标文件夹。 这应该不会产生任何问题。
  • 考虑将文件操作移出,并且仅使用流。 然后您可以轻松测试内存流上的压缩。 文件操作仍然需要在某个地方并且没有经过测试。

I would make these two static methods (ExtractZip and AddFileToZip) instance methods, and put it into an interface:

public interface IZipper
{
  void ExtractZip(string zipFilename, string folder);
  void AddFileToZip(string zipFilename, string fileToAdd);
}

public class Zipper : IZipper
{
  public void ExtractZip(string zipFilename, string folder)
  { 
    //...
  }

  void AddFileToZip(string zipFilename, string fileToAdd)
  {
    //...
  }
}


// client code
class Foo
{
  private IZipper myZipper;
  // gets an instance of the zipper (injection), but implements only 
  // against the interface. Allows mocks on the IZipper interface.
  public Foo(IZipper zipper)
  {
    myZipper = zipper;
  }

}

Client code is now easy to test.

What about the Zipper class?

  • Consider if it is worth to test anyway.
  • In our project, we distinguish between unit tests (isolated) and integration tests, where it is possible to use the database or the file system. You could declare it as an "file system integration test". Of course, only the test target folder is allowed to be used. This shouldn't make any problems.
  • Consider to move the file operations out, and only work with streams. Then you can easily test the zipping on memory streams. The file operations still need to be somewhere and aren't tested.
凹づ凸ル 2024-08-01 23:20:06

抽象出 IStreamProvider 后面 FileStream 的创建,并将其传递给 AddFileToZipExtractZip。 除非您愿意在进行单元测试时进行磁盘 IO,否则您必须抽象文件系统操作。

Abstract away the creation of FileStreams behind IStreamProvider and pass it to AddFileToZip and ExtractZip. You'll have to abstract filesystem operations unless you're willing to do disk IO while doing unit tests.

何以畏孤独 2024-08-01 23:20:06

我将最终的代码粘贴在这里,因为它可能会对某人有所帮助,并且还可以让我获得反馈。
感谢斯特凡为我指明了正确的方向。

<代码> <代码>

/// <summary>
/// The commented methods are marked for future
/// </summary>
public interface IZipper
{
    //void Create();
    void ExtractAll();
    void ExtractAll(string folder);
    //void Extract(string fileName);
    void AddFile(string fileName);
    //void DeleteFile(string fileName);
}
public interface IZipStreamProvider
{
    Stream GetStream(string fileName);
}

public class ZipStreamProvider : IZipStreamProvider
{
    public Stream GetStream(string fileName)
    {
        //Create a read/writable file
        return new FileStream(fileName, FileMode.Create);
    }
}

public class Zipper : IZipper
{
    private const long BufferSize = 4096;
    public string ZipFileName { get; set;}

    //seam.. to use property injection
    private IZipStreamProvider ZipStreamProvider { get; set;}

    public Zipper(string zipFilename)
    {
        ZipFileName = zipFilename;
        //By default, write to file
        ZipStreamProvider = new ZipStreamProvider();
    }

    public void ExtractAll()
    {
        ExtractAll(Environment.CurrentDirectory);
    }

    public void ExtractAll(string folder)
    {
        using (var zip = System.IO.Packaging.Package.Open(ZipStreamProvider.GetStream(ZipFileName)))
        {
            foreach (var part in zip.GetParts())
            {
                using (var reader = new StreamReader(part.GetStream(FileMode.Open, FileAccess.Read)))
                {
                    using (var writer = ZipStreamProvider.GetStream(folder + "\\" + Path.GetFileName(part.Uri.OriginalString)))
                    {
                        var buffer = System.Text.Encoding.UTF8.GetBytes(reader.ReadToEnd());
                        writer.Write(buffer, 0, buffer.Length);
                    }
                }
            }
        }
    }

    public void AddFile(string fileToAdd)
    {
        using (var zip = System.IO.Packaging.Package.Open(ZipFileName, FileMode.OpenOrCreate))
        {
            var destFilename = ".\\" + Path.GetFileName(fileToAdd);
            var uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
            if (zip.PartExists(uri))
            {
                zip.DeletePart(uri);
            }
            var part = zip.CreatePart(uri, "", CompressionOption.Normal);
            using (var fileStream = ZipStreamProvider.GetStream(fileToAdd))
            {
                using (var dest = part.GetStream())
                {
                    CopyStream(fileStream, dest);
                }
            }
        }
    }

    private long CopyStream(Stream inputStream, Stream outputStream)
    {
        var bufferSize = inputStream.Length < BufferSize ? inputStream.Length : BufferSize;
        var buffer = new byte[bufferSize];
        int bytesRead;
        var bytesWritten = 0L;
        while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) != 0)
        {
            outputStream.Write(buffer, 0, bytesRead);
            bytesWritten += bufferSize;
        }

        return bytesWritten;
    }
}

>

I'm pasting the final code here as it might help someone and also allow me to get feedback.
Thanks to Stefan for pointing me in the right direction.

/// <summary>
/// The commented methods are marked for future
/// </summary>
public interface IZipper
{
    //void Create();
    void ExtractAll();
    void ExtractAll(string folder);
    //void Extract(string fileName);
    void AddFile(string fileName);
    //void DeleteFile(string fileName);
}
public interface IZipStreamProvider
{
    Stream GetStream(string fileName);
}

public class ZipStreamProvider : IZipStreamProvider
{
    public Stream GetStream(string fileName)
    {
        //Create a read/writable file
        return new FileStream(fileName, FileMode.Create);
    }
}

public class Zipper : IZipper
{
    private const long BufferSize = 4096;
    public string ZipFileName { get; set;}

    //seam.. to use property injection
    private IZipStreamProvider ZipStreamProvider { get; set;}

    public Zipper(string zipFilename)
    {
        ZipFileName = zipFilename;
        //By default, write to file
        ZipStreamProvider = new ZipStreamProvider();
    }

    public void ExtractAll()
    {
        ExtractAll(Environment.CurrentDirectory);
    }

    public void ExtractAll(string folder)
    {
        using (var zip = System.IO.Packaging.Package.Open(ZipStreamProvider.GetStream(ZipFileName)))
        {
            foreach (var part in zip.GetParts())
            {
                using (var reader = new StreamReader(part.GetStream(FileMode.Open, FileAccess.Read)))
                {
                    using (var writer = ZipStreamProvider.GetStream(folder + "\\" + Path.GetFileName(part.Uri.OriginalString)))
                    {
                        var buffer = System.Text.Encoding.UTF8.GetBytes(reader.ReadToEnd());
                        writer.Write(buffer, 0, buffer.Length);
                    }
                }
            }
        }
    }

    public void AddFile(string fileToAdd)
    {
        using (var zip = System.IO.Packaging.Package.Open(ZipFileName, FileMode.OpenOrCreate))
        {
            var destFilename = ".\\" + Path.GetFileName(fileToAdd);
            var uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
            if (zip.PartExists(uri))
            {
                zip.DeletePart(uri);
            }
            var part = zip.CreatePart(uri, "", CompressionOption.Normal);
            using (var fileStream = ZipStreamProvider.GetStream(fileToAdd))
            {
                using (var dest = part.GetStream())
                {
                    CopyStream(fileStream, dest);
                }
            }
        }
    }

    private long CopyStream(Stream inputStream, Stream outputStream)
    {
        var bufferSize = inputStream.Length < BufferSize ? inputStream.Length : BufferSize;
        var buffer = new byte[bufferSize];
        int bytesRead;
        var bytesWritten = 0L;
        while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) != 0)
        {
            outputStream.Write(buffer, 0, bytesRead);
            bytesWritten += bufferSize;
        }

        return bytesWritten;
    }
}

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