2

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

前もって感謝します。

4

3 に答える 3

2

これらの2つの静的メソッド(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;
  }

}

クライアントコードのテストが簡単になりました。

ジッパークラスはどうですか?

  • とにかくテストする価値があるかどうかを検討してください。
  • 私たちのプロジェクトでは、データベースまたはファイルシステムを使用できる単体テスト(分離)と統合テストを区別します。「ファイルシステム統合テスト」として宣言することができます。もちろん、使用できるのはテスト対象フォルダのみです。これで問題が発生することはありません。
  • ファイル操作を移動し、ストリームでのみ機能することを検討してください。次に、メモリストリームの圧縮を簡単にテストできます。ファイル操作はまだどこかにある必要があり、テストされていません。
于 2009-07-08T10:03:34.363 に答える
0

FileStreamsの作成を抽象化してandIStreamProviderに渡します。単体テストの実行中にディスク IO を実行する意思がない限り、ファイルシステム操作を抽象化する必要があります。AddFileToZipExtractZip

于 2009-07-08T08:56:23.843 に答える
0

誰かを助け、フィードバックを得ることができるように、最終的なコードをここに貼り付けます。私を正しい方向に向けてくれたStefanに感謝します。

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

于 2009-07-08T12:07:52.977 に答える