Mockito #
Weshalb Mocks? #
Probleme von simplen Stubs:
- Können sehr komplex werden
- Müssen angepasst werden, wenn die Klasse, die gestubt wird, sich verändert.
Was ist ein Mock? #
Mocking is creating objects that simulate the behavior of real objects. Unlike stubs, mocks can be dynamically created from code - at runtime
Mocks offer more functionality than stubbing. You can verify method calls and a lot of other things.
Mock-Klasse generieren #
Zwei Methode:
-
Mittels statischer Methode
mock()
:Flower flowerMock=Mockito.mock(Flower.class);
-
Mittels
@Mock
-Annotation@Mock private Flower flowerMock;
Bei Letzterem ist es notwendig, entweder die Methode MockitoAnnotations.initMocks(testClass)
aufzurufen oder MockitoJUnit4Runner
als Junit-Runner zu verwenden
Basics #
Mockito gibt standardmässig Nice Mocks zurück (bspw. eine leere Liste, wenn eine Liste als Rückgabewert erwartet wird).
when…thenReturn #
when(<auszführende_methode>).thenReturn(<zurückzugebender_wert>)
. Bspw.:
@Test
public void test() {
List listMock = mock(List.class);
when(listMock.size()).thenReturn(2);
assertEquals(2, listMock.size());
}
thenReturn()
kann auch mehrfach verwendet werden. Die entsprechenden Werte werden dann seriell ausgegeben.
Argument Matcher #
Argument Matcher sind Funktionen, welche eine Reihe von Werte zurückgeben, bspw. anyInt()
für alle Integers oder anyObjects()
für alle Java-Objekte.
thenThrow #
Gibt eine Exception zurück (das bspw. mit JUnit-Annotation @Test(expected=RuntimeException.class)
getestet werden kann).
verify #
verify
überprüft, ob eine bestimmte Methode des Mock aufgerufen wird (= überprüfen von Seiteneffekte). Syntax
verify(<mock>, <optionale_anzahl_aufrufe>).<zu_testende_methode()>
Anzahl kann bspw. sein:
never()
times(...)
atLeast(...)
- etc.
- Standardmässig mindestens einmal (
atLeastOnce()
)
Alternativ kann auch - als Nicht-BDD-Stil - verwendet werden: then(<mock>).should(<optionale_anzahl_aufrufe>).<zu_testende_methode()>
Argumente abfangen #
Dazu sind drei Dinge nötig:
ArgumentCaptor
definieren, bspw.ArgumentCaptor<Stirng> stringArgumentCaptor = ArgumentCaptor.forClass(String.class)
(für Alternative s. Abschnitt Annotationen)capture()
-Methode als Argument ausführen, bspw.then(todoServiceMock).should().deleteTodo(stringArgumentCaptor.capture())
getValue()
-Methode in Assertion ausführen, bspw.assertThtat(stringArgumentCaptor.getValue(), is("Learn to dance"))
.Alternativ gibt es auch MethodengetAllValues()
in Verbindung mit einersize()
-Methode, die zur Anwendung kommt, wenn mehrere Argumente getestet werden sollen
Annotationen #
Mockito kommt mit einer Reihe von Annotationen, z.B. @Mock
, @InjectMocks
, @RunWith
, @Captor
@Mock
: s. oben in Abschnitt Mock-Klasse generieren@InjectMocks
: Injiziert automatisch Abhängigkeiten, welche die zu testende Klasse hat und welche als Mock in der Test-Klasse definiert werden. Damit entfällt eine Zeile à la newTodoBusinessImpl todoBusinessImpl = TodoBusinessImpl(todoServiceMock);
@Captor
: Erstellt automatisch einen Captor zu einem Typ, bspw.@Captor ArgumentCaptor<String> stringArgumentCaptor;
Spy #
- Spies werden mit der statischen Methode
spy
erstellt. Im Gegensatz zumock
wird die mitgegebene Klasse tatsächlich erstellt, bspw.ArrayList
inspy(ArrayList.class);
- Werden auch als Partial Mock bezeichnet, da sie Teil Mock, Teil wirkliche Klasse sind
- Verhalten der Klasse kann überschrieben werden
- Spies sollten eher vermieden werden, da der hybride Charakter von Spies Komplexität hineinbringt und der Nutzen (beobachten von Verhalten der Dependency) beschränkt ist
BDD Mockito #
Stellt Test-Setups in der Form given
(Setup) - when
(SUT ausführen) - then
(Assertion) zur Verfügung:
given(...).willReturn(..)
anstelle vonwhen(...).thenReturn(...)
- Neue Assertions, bspw.
assertThat(..., is(...))
- Basiert z.T. auf Hamcrest-Matchers
Einschränkungen (per Design) #
final
-Klassen/-Methoden können nicht verwendet werdenprivate
-Klassen/-Methoden können nicht verwenet werden
Um diese Einschränkungen zu umgehen, PowerMock benutzen