Mockito

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 Methoden getAllValues() in Verbindung mit einer size()-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 new TodoBusinessImpl 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 zu mock wird die mitgegebene Klasse tatsächlich erstellt, bspw. ArrayList in spy(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 von when(...).thenReturn(...)
  • Neue Assertions, bspw. assertThat(..., is(...))
  • Basiert z.T. auf Hamcrest-Matchers

Einschränkungen (per Design) #

  • final-Klassen/-Methoden können nicht verwendet werden
  • private-Klassen/-Methoden können nicht verwenet werden

Um diese Einschränkungen zu umgehen, PowerMock benutzen