あなたの質問は、開発者がそれに入るだけのテストの最も難しい部分の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あなたのメソッドの名前である(あるいは少なくともそれはする必要があります)。どのようにすべてのあなたの方法の内側に住む小さな実装の詳細です。優れたテストでは、WHATを壊すことなくHOWを交換できます。
このように考えて、自問してみてください。
「(パブリックコントラクトを変更せずに)このメソッドの実装の詳細を変更すると、テストが失敗しますか?」
答えが「はい」の場合は、WHATではなくHOWをテストしています。
ファイルシステムの依存関係を使用したコードのテストに関する特定の質問に答えるために、ファイルで少し興味深いことがあり、Base64でエンコードされたコンテンツをbyte[]
ファイルに保存したいとします。これにストリームを使用して、コードがどのように動作するかを確認する必要なく、コードが正しいことをテストできます。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");
}
テストではaを使用しますByteArrayOutputStream
が、アプリケーションでは(依存関係の注入を使用して)実際のStreamFactory(おそらくFileStreamFactoryと呼ばれる)はFileOutputStream
から戻りoutputStream()
、に書き込みFile
ます。
write
ここでのメソッドの興味深い点は、Base64でエンコードされたコンテンツを書き込むことでした。そのため、これをテストしました。あなたのDoIt()
方法では、これは統合テストでより適切にテストされます。