Mockito ist ein Open-Source-Framework zum Erstellen von Mock-Objekten in Java- und Kotlin-Komponententests, das es ermöglicht, den getesteten Code von externen Abhängigkeiten zu isolieren. Mit seiner Hilfe ersetzt der Entwickler echte Repositories, API-Clients und Datenbanken durch kontrollierte Stubs mit vordefiniertem Verhalten. Laut Mockito.org wird die Bibliothek in mehr als 60% der Java-Projekte verwendet, die Komponententests einsetzen.
Wichtige Punkte
Mockito ist eine Open-Source-Bibliothek zum Erstellen von Mock-Objekten (Stubs) in Komponententests für Java, Kotlin und andere JVM-Sprachen. Im Gegensatz zu JUnit, das für die Testausführung zuständig ist, löst Mockito das Problem der Isolation — es ersetzt die echten Abhängigkeiten der getesteten Klasse durch vorhersagbare Objekte.
Ohne Mocks erfordert das Testen einer Methode, die auf eine Datenbank oder externe API zugreift, die Einrichtung einer realen Umgebung — Bereitstellen einer Datenbank, Starten eines Servers. Mockito ersetzt diese Abhängigkeiten durch Objekte mit festgelegtem Verhalten: Die Methode repository.findById(1) gibt immer ein bestimmtes User-Objekt zurück, ohne auf die Datenbank zuzugreifen.
Die Architektur von Mockito basiert auf dem Proxy-Muster (für Schnittstellen und Klassen). Die Bibliothek generiert eine Unterklasse oder einen Proxy für den angegebenen Typ und fängt alle Methodenaufrufe ab, wobei sie Standardwerte oder über when().thenReturn() festgelegte Werte zurückgibt.
Das Prinzip der Funktionsweise von Mockito basiert auf drei grundlegenden Operationen: Erstellen des Mocks, Konfigurieren des Verhaltens (Stubbing) und Überprüfen von Aufrufen (Verification). Jede Operation verwendet statische Methoden aus der Klasse org.mockito.Mockito — der am häufigsten heruntergeladenen Klasse im Java-Ökosystem laut Maven-Central-Statistiken. Alle Methodenaufrufe des Mocks werden im Speicher aufgezeichnet, was eine spätere Überprüfung durch verify ermöglicht.
Ein typischer Test mit Mockito besteht aus drei Phasen: Arrange — Erstellen von Mocks und Konfigurieren von Stubs über when().thenReturn(), Act — Aufruf der getesteten Methode, Assert — Überprüfung des Ergebnisses über assertEquals und verify(mock). Dieser Ansatz wird AAA (Arrange-Act-Assert) genannt.
Betrachten wir einen einfachen Test, bei dem Mockito ein Benutzer-Repository ersetzt. Die Methode when().thenReturn() konfiguriert den Mock so, dass der findById-Aufruf ein vorbereitetes User-Objekt zurückgibt.
// Repository-Mock erstellen
UserRepository mockRepo = mock(UserRepository.class);
// Verhalten konfigurieren: findById(1) gibt einen Benutzer zurück
when(mockRepo.findById(1)).thenReturn(new User("Alice"));
// Überprüfen, dass die Methode tatsächlich aufgerufen wurde
User result = mockRepo.findById(1);
assertEquals("Alice", result.getName());
verify(mockRepo).findById(1);
Mockito bietet zwei Möglichkeiten zum Erstellen von Mocks: die statische Methode mock(Class) und die Annotation @Mock mit Initialisierung über MockitoAnnotations.openMocks(). Der erste Ansatz ist kompakt für ein oder zwei Mocks, der zweite ist praktisch, wenn viele Abhängigkeiten bestehen — Annotationen reduzieren den Boilerplate-Code.
Die Methode mock() nimmt eine Klasse entgegen und gibt ein Stub-Objekt zurück, das über when().thenReturn() konfiguriert werden kann. Alle nicht konfigurierten Methoden geben Standardwerte zurück: 0 für Zahlen, false für boolean, null für Objekte.
ApiClient apiClient = mock(ApiClient.class);
Database database = mock(Database.class);
Die Annotation @Mock in Kombination mit @ExtendWith(MockitoExtension.class) erstellt automatisch Mocks für alle Felder der Testklasse. Die MockitoExtension ist für die Initialisierung vor jedem Test verantwortlich.
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void getUserShouldReturnUserFromRepo() {
when(userRepository.findById(1)).thenReturn(new User("Alice"));
User result = userService.getUser(1);
assertEquals("Alice", result.getName());
}
}
Stubbing ist der Prozess der Definition, was eine Mock-Methode zurückgeben soll, wenn sie mit bestimmten Argumenten aufgerufen wird. Die grundlegende Syntax: when(mock.method(args)).thenReturn(value). Für verschiedene Szenarien bietet Mockito mehrere Varianten von then-Methoden.
| Methode | Zweck |
|---|---|
| thenReturn(value) | Gibt immer den angegebenen Wert zurück |
| thenThrow(exception) | Wirft eine Ausnahme beim Aufruf |
| thenAnswer(answer) | Berechnet den Rückgabewert dynamisch |
| thenCallRealMethod() | Ruft die echte Methode auf (teilweiser Mock) |
Wenn der Rückgabewert von den Aufrufargumenten abhängt, wird thenAnswer mit einem Lambda verwendet. Dies ist nützlich, um die Arbeit mit echten Daten zu simulieren — beispielsweise das Generieren einer ID basierend auf dem übergebenen Objekt.
when(repository.save(any())).thenAnswer(invocation -> {
User user = invocation.getArgument(0);
user.setId(42);
return user;
});
Verify ist eine einzigartige Funktion von Mockito, die ältere Mock-Objekt-Bibliotheken (EasyMock, jMock) nicht bieten.
Verify macht Tests zuverlässiger, weil es nicht nur den Rückgabewert, sondern auch Seiteneffekte — Aufrufe von Methoden, die kein Ergebnis zurückgeben (void-Methoden) — überprüft. Die Methode verify(mock).methodName(args) prüft, ob eine bestimmte Mock-Methode mit den angegebenen Argumenten aufgerufen wurde. Dies ermöglicht es, nicht nur das Ergebnis, sondern auch den Prozess zu testen — die Tatsache des Zugriffs auf die Abhängigkeit.
Standardmäßig prüft verify, dass die Methode genau einmal aufgerufen wurde. Wenn eine andere Anzahl benötigt wird, werden times(n), atLeast(n), never() und andere Modifikatoren aus der Klasse Mockito verwendet.
// Überprüfung der Anzahl der Aufrufe
verify(repository, times(3)).save(any());
verify(repository, never()).delete(any());
verify(repository, atLeastOnce()).findById(1);
// Überprüfung der Reihenfolge der Aufrufe
InOrder inOrder = inOrder(repository);
inOrder.verify(repository).save(any());
inOrder.verify(repository).flush();
Wenn Sie überprüfen müssen, mit welchem genauen Objekt eine Methode aufgerufen wurde, wird ArgumentCaptor verwendet. Es erfasst den Argumentwert während des Aufrufs und ermöglicht die überprüfung seiner Felder einzeln. ArgumentCaptor ist besonders nützlich, wenn der getestete Code intern ein Objekt erstellt und es an eine Abhängigkeit übergibt — Sie können dieses Objekt sonst nicht überprüfen.
ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);
verify(repository).save(captor.capture());
assertEquals("Alice", captor.getValue().getName());
@Mock und @InjectMocks sind zwei wichtige Mockito-Annotationen, die Boilerplate-Code erheblich reduzieren. @Mock erstellt einen Mock für ein Feld, und @InjectMocks injiziert alle Mocks aus der Testklasse in das getestete Objekt über Konstruktor, Setter oder Feld.
Der Mechanismus von @InjectMocks versucht, Abhängigkeiten in der folgenden Reihenfolge zu injizieren: Konstruktor mit den meisten Argumenten, Setter nach Typ, privates Feld. Wenn keine dieser Methoden funktioniert, bleibt das Objekt mit null-Abhängigkeiten zurück, und der Test schlägt mit einer NullPointerException fehl.
Es ist wichtig zu verstehen: @InjectMocks analysiert keine Feldtypen — es ersetzt jeden Mock, der vom Typ her kompatibel ist. Wenn eine Klasse zwei Felder desselben Typs hat, kann Mockito den falschen Mock injizieren. In solchen Fällen wird empfohlen, einen expliziten Konstruktor mit Mock-Parametern zu verwenden.
In der Android-Entwicklung wird Mockito zusammen mit JUnit zum Testen von ViewModel, Repository und UseCase verwendet. Da diese Klassen auf der JVM ohne Android-Kontext ausgeführt werden, ersetzt Mockito ihre Abhängigkeiten — Room DAO, Retrofit API, SharedPreferences — durch Stubs mit vorhersagbarem Verhalten.
Um Mockito zu einem Android-Projekt hinzuzufügen, fügen Sie einfach die Abhängigkeit mockito-core oder mockito-inline hinzu (letztere unterstützt das Mocken von finalen Klassen und statischen Methoden). Version 5.12.0 (2024) enthält Java-21-Unterstützung und eine verbesserte JUnit-5-Integration.
// build.gradle.kts (module)
dependencies {
testImplementation("org.mockito:mockito-core:5.12.0")
testImplementation("org.mockito:mockito-junit-jupiter:5.12.0")
}
Früher war für das Mocken von statischen Methoden und Konstruktoren PowerMock erforderlich — eine Erweiterung, die durch Bytecode-Instrumentierung funktionierte. Ab Mockito 5.x mit mockito-inline ist diese Fähigkeit direkt integriert: mockStatic(ClassName.class) ermöglicht das Mocken von statischen Methoden ohne zusätzliche Bibliotheken.
Ein typisches Szenario: Ein ViewModel ruft eine Repository-Methode auf und transformiert das Ergebnis in einen UI-Zustand. Mockito ersetzt das Repository, und der Test überprüft, ob das ViewModel sowohl die erfolgreiche Antwort als auch den Fehler korrekt behandelt. Bei Verwendung der Clean Architecture werden Mocks für jede Schicht erstellt: DataSource, Repository und UseCase — dies ermöglicht es, jede Schicht isoliert zu testen.
Häufig gestellte Fragen
Mockito ist eine Bibliothek für Java und Kotlin, die Proxys und Reflektion verwendet. MockK ist eine Kotlin-First-Bibliothek mit Unterstützung für Coroutinen, Erweiterungsfunktionen und finale Klassen ohne zusätzliche Konfiguration.
Ab Mockito 2.1 wird das Mocken von finalen Klassen durch Opt-in unterstützt. In Version 5.x (mockito-inline) ist dies standardmäßig aktiviert. Fügen Sie einfach die Abhängigkeit mockito-inline hinzu und verwenden Sie die Standard-mock()-Methode.
Ein Spy ist ein teilweiser Mock, der standardmäßig echte Methoden aufruft, aber einige von ihnen über when().thenReturn() überschreiben kann. Spy ist nützlich zum Testen von Legacy-Code, wenn die gesamte Klasse nicht umgeschrieben werden kann.
thenReturn gibt immer denselben Wert zurück, unabhängig von den Argumenten. thenAnswer berechnet den Rückgabewert basierend auf der Invocation — Aufrufargumente, der Mock selbst und Zustand. Für dynamische Antworten verwenden Sie immer thenAnswer.
Verify überprüft nicht nur das Ergebnis, sondern auch den Prozess — die Tatsache des Zugriffs auf die Abhängigkeit. Dies ist entscheidend für Dienste, die Daten speichern oder Benachrichtigungen senden müssen. Ohne verify erkennt der Test nicht, dass eine Methode save() oder send() nicht aufgerufen hat.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch