Próbuję użyć Mockito do wyśmiewania klasy typu "Czytnik". Pomyśl o czytniku strumienia danych, ma on metody odczytywania różnych typów danych i przesuwania wewnętrznego wskaźnika po każdym odczycie.Modułowe wywoływanie kolejnych wywołań metod za pomocą Mockito
public interface Reader {
int readInt();
short readShort();
}
Testowana klasa odczytuje różne struktury danych ze strumienia danych. Na przykład,
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);
}
}
I wreszcie, mam Test:
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);
}
}
Niestety, to nie zadziała. read.readInt() zawsze zwraca 6 dla każdego wywołania. I rozumiem, dlaczego to zwraca 6. To nie jest moje pytanie.
Są dwie opcje, które mogę naprawić, ale nie podoba mi się żadna z nich.
Pierwszą opcją byłoby coś takiego:
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));
}
}
To powinno działać, ale to bardzo monolityczny i niechlujny. Trudno zobaczyć, który powrót jest dla jakiego kawałka tej struktury, ponieważ wszystkie są wymieszane, bez żadnej struktury.
Druga opcja można myślę, jest coś takiego:
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);
}
}
Tak przynajmniej utrzymuje strukturę oryginału, ale mający zdać osobny obiekt dla każdej metody zadzwonić chcesz, aby na zgaszone obiekt to ... ugh.
Jaki byłby najczystszy sposób na wykonanie tego testu? Czy jest tu jakaś opcja, której tu brakuje? Jakie funkcje mogę wykorzystać? Właśnie zacząłem używać Mockito dziś wieczorem, więc mogłem bardzo dobrze czegoś przegapić.
Tak jak wspomniałem, wiem, że jedna z dwóch alternatyw, o których wspomniałem, zadziała, ale nie dbam o żadną z nich. Wystarczy zmienić serię .thenReturn (1). ThenReturn (2) na .thenReturn (1, 2) w żaden sposób nie poprawi jej struktury :) – JesusFreke
Dlatego właśnie zaproponowałem, aby przetoczyć własne jako alternatywę. – Lunivore