あなたの質問は、開発者にとってテストの最も難しい部分の1つを明らかにしています。
「一体何をテストするのですか?」
あなたの例は、いくつかの API 呼び出しを結合するだけなので、あまり興味深いものではありません。そのため、単体テストを作成すると、メソッドが呼び出されたことをアサートすることになります。このようなテストは、実装の詳細をテストに密接に結合します。実装の詳細を変更するとテストが壊れるため、メソッドの実装の詳細を変更するたびにテストを変更する必要があるため、これは悪いことです。
悪いテストを行うことは、テストをまったく行わないことよりも実際には悪いことです。
あなたの例では:
void DoIt(IZipper zipper, IFileSystem fileSystem, IDllRunner runner)
{
string path = zipper.Unzip(theZipFile);
IFakeFile file = fileSystem.Open(path);
runner.Run(file);
}
モックを渡すことはできますが、テストするメソッドにはロジックがありません。これについて単体テストを試みるとしたら、次のようになります。
// Assuming that zipper, fileSystem, and runner are mocks
void testDoIt()
{
// mock behavior of the mock objects
when(zipper.Unzip(any(File.class)).thenReturn("some path");
when(fileSystem.Open("some path")).thenReturn(mock(IFakeFile.class));
// run the test
someObject.DoIt(zipper, fileSystem, runner);
// verify things were called
verify(zipper).Unzip(any(File.class));
verify(fileSystem).Open("some path"));
verify(runner).Run(file);
}
おめでとうございます。基本的に、メソッドの実装の詳細をコピーDoIt()
してテストに貼り付けました。ハッピーメンテ。
テストを作成するときは、 HOWではなくWHATをテストする必要があります。
詳細については、ブラック ボックス テストを参照してください。
WHATはメソッドの名前です (または、少なくともそうあるべきです)。HOWは、メソッド内に存在するすべての小さな実装の詳細です。優れたテストでは、 WHATを壊さずにHOWを入れ替えることができます。
このように考えて、次のように自問してください。
「このメソッドの実装の詳細を (パブリック コントラクトを変更せずに) 変更すると、テストが中断されますか?」
答えが「はい」の場合、 WHATではなくHOWをテストしています。
ファイル システムの依存関係を使用したコードのテストに関する特定の質問に答えるために、ファイルでもう少し興味深いことがあり、Base64 でエンコードさbyte[]
れた a のコンテンツをファイルに保存したいとします。これにストリームを使用して、コードがどのように動作するかを確認することなく、コードが正しい動作をするかどうかをテストできます。1つの例は、次のようなものです(Javaで):
interface StreamFactory {
OutputStream outStream();
InputStream inStream();
}
class Base64FileWriter {
public void write(byte[] contents, StreamFactory streamFactory) {
OutputStream outputStream = streamFactory.outStream();
outputStream.write(Base64.encodeBase64(contents));
}
}
@Test
public void save_shouldBase64EncodeContents() {
OutputStream outputStream = new ByteArrayOutputStream();
StreamFactory streamFactory = mock(StreamFactory.class);
when(streamFactory.outStream()).thenReturn(outputStream);
// Run the method under test
Base64FileWriter fileWriter = new Base64FileWriter();
fileWriter.write("Man".getBytes(), streamFactory);
// Assert we saved the base64 encoded contents
assertThat(outputStream.toString()).isEqualTo("TWFu");
}
テストでは を使用しますByteArrayOutputStream
が、アプリケーション (依存性注入を使用) では、実際の StreamFactory (おそらく FileStreamFactory と呼ばれる) がFileOutputStream
から戻り、outputStream()
に書き込みFile
ます。
このメソッドで興味深いのは、write
Base64 でエンコードされたコンテンツを書き込んでいたことです。これをテストしたのです。あなたの方法では、これは統合テストDoIt()
でより適切にテストされます。