Mockito Framework

Christoph Gächter

Die Herausforderung bei Unit Tests besteht darin, die Klasse isoliert zu testen, sprich ohne Nebeneffekte von anderen Klassen und unabhängig von anderen Systemen. Mockito bietet dazu ein umfangreiches Framework an, welches zusammen mit JUnit sehr einfach und effizient eingesetzt werden kann.


Typisches Vorgehen beim Testen mit Mockito:
1. Die Abhängigkeiten werden gemockt bzw. im Test werden die Mocks verwendet
2. Der oder die Test(s) wird / werden ausgeführt
3. Die Ausführung wird überprüft

Mockito im Projekt hinzufügen

Exemplarisch wird hier die Einbindung in Maven gezeigt:

Die zu testende Klasse

Die zu testende Klasse HealthCheck verwendet die beiden Services PersonService und MailService , die im Unit Test gemockt werden. Damit kann die Klasse HealthCheck isoliert betrachtet werden:

Die Methode getBMI() berechnet den Body Mass Index (BMI) einer Person. Dazu wird der Personen-Service aufgerufen, welcher Gewicht und Grösse der Person zurück gibt. Die Methode getAvgMass() berechnet zu Statistikzwecken das Durchschnittsgewicht aller Personen. Wiederum wird der Personen-Service verwendet, um das Gewicht der einzelnen Person zu bestimmen.

Erste Schritte mit Mockito

Die Testklasse HealthCeckTest initialisiert die Services und das Testframework, danach können die einzelnen Testfälle ausgeführt werden.

Die beiden Services PersonService und MailService werden mit der Annotation @Mock gekennzeichnet, um diese Objekte als Mocks zu erstellen. Die Regel MockitoRule , annotiert mit @Rule , führt die Initialisierung von Mockito aus. Dabei werden die Mocks erstellt sowie die zu testenden Klasse HealthCheck instanziiert unter Anwendung von Dependency Injection. Alternativ zur Regel kann auch in der Methode setUp() die Initialisierung von Mockito durchgeführt werden:

In der Methode setUp() wird das gewünschte Verhalten des Personen-Service definiert, indem je nach Person, die den Methoden getMass() bzw. getSize() übergeben wird, deren Grösse bzw. Gewicht zurückgegeben wird.

Erster Test

Der eigentliche Test findet in der Methode testGetBMI() statt: Für die vier vordefinierten  Personen wird der BMI berechnet und gegen das erwartete Resultat validiert. Schliesslich kann via Mockito geprüft werden, wie oft die beiden Service Methoden getMass() und getSize() aufgerufen worden sind, in unserem Beispiele je vier Mal.

Zweiter Test

In einem zweiten Test soll das Durchnittsgewicht aller Personen bestimmt werden. Dazu werden im Test Setup die Liste der Personen dem Testobjekt mitgegeben:

Das berechnete Durchschnittsgewicht wird mit dem erwarteten Wert verglichen. Weiter kann geprüft werden, wie oft die Service Methoden aufgerufen worden sind. Mockito stellt dabei verschiedene Prüfmethoden zur Verfügung:

  • Mockito.never() : nie aufgerufen
  • Mockito.atLeastOnce() : mindestens ein Mal aufgerufen
  • Mockito.atLeast(n) : mindestens n Mal aufgerufen
  • Mockito.atMost(n) : maximal n Mal aufgerufen
  • Mockito.times(n) : genau n Mal aufgerufen

Weitere Mockito Features…

Die ersten Schritte haben hoffentlich Spass gemacht, so dass wir hier weitere Features von Mockito anschauen wollen, insbesondere ArgumentMatchers, ArgumentCaptor , Mockito.doThrow() und Mockito.doAnswer() . Zuerst erweitern wir die Klasse HealthCheck um zwei weitere Methoden: Die Methode  setCallDate() setzt bei allen Personen mit BMI > 25 ein Datum zur Terminvereinbarung. Gleichzeitig wird ein Mail an diese Person versendet. Die Methode getCallDatePersons() sucht alle Personen, welche zu einem definierten Datum eine Terminvereinbarung gesetzt haben.

Dritter Test

Die Klasse ArgumentCaptor erlaubt den Zugriff auf Methodenargumente während der Testausführung. Wir definieren ein Argument Captor für die Klasse CallDate , welche im Service Call setCallDate(CallDate callDate) verwendet wird:

Und die Testmethode:

Der Aufruf der Methode und die Verifikation der Anzahl Service Calls haben wir bereits in den ersten Schritten mit Mockito kennen gelernt. Neu in dieser Testmethode ist das Call Argument callDate , welches gepüft werden kann: Wir erwarten, dass der Service Call mit der Person FRITSCHI ausgeführt worden ist, das genaue Datum interessiert uns jedoch nicht – dieses wird lediglich auf NotNull geprüft.

Da der Service Call setCallDate() genau einmal ausgeführt worden ist, enthält das Call Argument auch nur einen Wert. Würde der Service Call mehrmals ausgeführt, könnten im Test auch mehrere Werte geprüft werden:

Zudem wird in dieser Testmethode geprüft, ob und wie oft der Mail Service aufgerufen worden ist. Dabei interessiert uns wiederum nur die Person, mit welcher der Service Call ausgeführt worden ist. Das Datum kann beliebig sein. Rein intuitiv würde die Methode Mockito.verify() wie folgt
aufgerufen:

Vierter Test

Im nächsten Beispiel fragen wir uns, wie die getestete Klasse auf eine Exception des Service reagiert.

Mit der Anweisung Mockito.doThrow() definieren wir, dass der Service Call getCallDatePersons() die angegebene Exception werfen soll. Da unsere getestete Klasse kein Exception Handling implementiert, gelangt die Exception zur Testmethode, was soweit dem erwarteten Verhalten entspricht. Deshalb wird die Testmethode zusätzlich mit der erwarteten Exception annotiert.

Fünfter Test

Im letzten Beispiel soll der Personen-Service eine Liste von Personen zurückgeben, aus welchen jene Personen gefiltert werden, mit welchen heute ein Termin vereinbart werden soll.

Mit der Anweisung Mockito.doAnswer() definieren wir, dass der Service Call getCallDatePersons() eine Liste von Personen zurück gibt, jedoch nur bei einer Person die Teminvereinbarung heute stattfinden soll. Interessant bei dieser Anweisung ist, dass allfällige Call Argumente als InvocationOnMock -Objekt mitgegeben und in der Methode answer() ausgewertet werden können. Damit ist ein dynamisches Verhalten zur Laufzeit möglich.

…und noch mehr Features

In diesem Artikel werden nur einige wesentliche Features von Mockito eingeführt, um den Einstieg
in dieses weit verbreitete Framework zu vereinfachen. Aber es gibt noch viele Features, die hier
nicht besprochen worden sind oder die beliebig vertieft werden können, z.B.

  • Mock vs. spy
  • Call real method in mock
  • Custom argument matchers

Einschränkungen von Mockito

Das Mockito Framework ist sehr mächtig und wurde in Version 2 deutlich erweitert. Trotzdem müssen zwei Limitationen erwähnt werden, welche bei der Evaluation und Verwendung dieses Testframeworks beachtet werden müssen:

    1. Statische Methoden können nicht gemockt werden.
    2. Private Methoden können nicht gemockt werden.

Als alternatives Testframework kann hier PowerMock verwendet werden.

Quellen und weitere Informationen

Schreibe einen Kommentar