1. ホーム
  2. unit-testing

[解決済み] ファイルシステムに依存するコードの単体テスト

2022-04-30 17:57:50

質問

私は、ZIPファイルが与えられると、それが必要なコンポーネントを書いています。

  1. ファイルを解凍します。
  2. 解凍されたファイルの中から特定のDLLを検索します。
  3. リフレクションによってそのDLLをロードし、そのDLL上のメソッドを呼び出す。

このコンポーネントをユニットテストしたいのですが。

ファイルシステムを直接処理するコードを書きたくなった。

void DoIt()
{
   Zip.Unzip(theZipFile, "C:\\foo\\Unzipped");
   System.IO.File myDll = File.Open("C:\\foo\\Unzipped\\SuperSecret.bar");
   myDll.InvokeSomeSpecialMethod();
}

しかし、「ファイルシステム、データベース、ネットワークなどに依存するユニットテストは書くな」とよく言われます。

これをユニットテストに適した形で書くとしたら、こんな感じになるんでしょうかね。

void DoIt(IZipper zipper, IFileSystem fileSystem, IDllRunner runner)
{
   string path = zipper.Unzip(theZipFile);
   IFakeFile file = fileSystem.Open(path);
   runner.Run(file);
}

やったー これでテストが可能になりました。DoItメソッドにテスト用のダブル(モック)を送り込めばいいのです。しかし、その代償は?これをテスト可能にするために、3つの新しいインターフェイスを定義しなければならなくなったのです。そして、私は何をテストしているのでしょうか?DoIt関数が依存関係にある関数と適切に相互作用することをテストしているのです。zip ファイルが正しく解凍されたかどうかなどはテストしていません。

もう、機能をテストしている感覚はないですね。ただクラスのインタラクションをテストしているようにしか感じられない。

私の疑問はこれ : ファイルシステムに依存するものをユニットテストする適切な方法は何でしょうか?

編集 私は.NETを使用していますが、コンセプトはJavaやネイティブコードにも適用できます。

どのように解決するのですか?

これは本当に何も問題ありません。ただ、これをユニットテストと呼ぶか、統合テストと呼ぶかが問題なのです。 ただ、ファイルシステムとやりとりするときに、意図しない副作用がないことを確認する必要があります。 特に、作成した一時ファイルを削除するなどの後始末をしっかり行い、たまたま使っていた一時ファイルと同じファイル名の既存のファイルを誤って上書きしないようにしましょう。 また、絶対パスではなく、必ず相対パスを使用してください。

また、以下のようにするとよいでしょう。 chdir() をテスト実行前に一時ディレクトリにコピーし chdir() を返します。