Mockito を使用して「リーダー」型クラスをモックしようとしています。データストリームリーダーを考えてみてください。さまざまなデータ型を読み取り、読み取りごとに内部ポインターを進めるメソッドがあります。
public interface Reader {
int readInt();
short readShort();
}
テスト対象のクラスは、データ ストリームからさまざまなデータ構造を読み取ります。例えば、
public class Somethings {
public List<Something> somethings;
public Somethings(Reader reader) {
somethings = new List<Something>();
int count = reader.readInt();
for (int i=0; i<count; i++) {
somethings.add(readSomething(reader));
}
}
private Something readSomething(Reader reader) {
int a = reader.readInt();
short b = reader.readShort();
int c = reader.readInt();
return new Something(a, b, c);
}
}
最後に、テストがあります。
public class SomethingsTest {
@Test
public void testSomethings() {
Reader reader = Mockito.mock(Reader.class);
readCount(reader, 2);
readSomething(reader, 1, 2, 3);
readSomething(reader, 4, 5, 6);
Somethings somethings = new Somethings(reader);
Assert.assertEqual(2, somethings.size());
Assert.assertEquals(new Something(1, 2, 3), somethings.somethings.get(0));
Assert.assertEquals(new Something(4, 5, 6), somethings.somethings.get(1));
}
private void readCount(Reader reader, int count) {
when(reader.readInt()).thenReturn(count);
}
private void readSomething(Reader reader, int a, short b, int c) {
when(reader.readInt()).thenReturn(a);
when(reader.readShort()).thenReturn(b);
when(reader.readInt()).thenReturn(c);
}
}
残念ながら、これは機能しません。reader.readInt() は、呼び出しごとに常に 6 を返します。そして、6 が返される理由を理解しています。それは私の質問ではありません。
テストを修正するために考えられる 2 つのオプションがありますが、どちらも特に好きではありません。
最初のオプションは次のようになります。
public class SomethingsTest {
@Test
public void testSomethings() {
Reader reader = Mockito.mock(Reader.class);
when(reader.readInt())
.thenReturn(2)
.thenReturn(1)
.thenReturn(3)
.thenReturn(4)
.thenReturn(6);
when(reader.readShort())
.thenReturn(2)
.thenReturn(5);
Somethings somethings = new Somethings(reader);
Assert.assertEqual(2, somethings.size());
Assert.assertEquals(new Something(1, 2, 3), somethings.somethings.get(0));
Assert.assertEquals(new Something(4, 5, 6), somethings.somethings.get(1));
}
}
これは機能するはずですが、非常にモノリシックで面倒です。どのリターンがどのストラクチャーのどの部分に対するものかを確認するのは困難です。なぜなら、それらはすべて混ざり合っており、ストラクチャーがないからです。
私が考えることができる2番目のオプションは次のようなものです:
public class SomethingsTest {
@Test
public void testSomethings() {
Reader reader = Mockito.mock(Reader.class);
NewOngoingStubbing readIntStub = when(reader.readInt());
NewOngoingStubbing readShortStub = when(reader.readShort());
readCount(readIntStub, 2);
readSomething(readIntStub, readShortStub, 1, 2, 3);
readSomething(readIntStub, readShortStub, 4, 5, 6);
Somethings somethings = new Somethings(reader);
Assert.assertEqual(2, somethings.size());
Assert.assertEquals(new Something(1, 2, 3), somethings.somethings.get(0));
Assert.assertEquals(new Something(4, 5, 6), somethings.somethings.get(1));
}
private void readCount(NewOngoingStubbing readIntStub, int count) {
readIntStub.thenReturn(count);
}
private void readSomething(NewOngoingStubbing readIntStub,
NewOngoingStubbing readShortStub, int a, short b, int c) {
readIntStub.thenReturn(a);
readShortStub.thenReturn(b);
readIntStub.thenReturn(c);
}
}
これにより、少なくとも元の構造が維持されますが、スタブ化されたオブジェクトに対して行うメソッド呼び出しごとに個別のオブジェクトを渡す必要があるのは... うーん。
このテストを実行する最もクリーンな方法は何ですか? ここに欠けているオプションはありますか?活用できる機能はありますか? 今夜Mockitoを使い始めたばかりなので、何かが足りない可能性があります。