Wenn du mit Java Tests schreibst, stößt du ziemlich schnell auf ein Problem: Deine Klasse arbeitet oft nicht allein. Sie ruft andere Klassen auf, spricht vielleicht mit einer Datenbank, nutzt eine externe API oder verschickt Nachrichten. Genau an der Stelle kommt Mockito ins Spiel.

Mockito ist eine Java-Bibliothek für Tests. Mit ihr kannst du sogenannte Mocks erzeugen. Ein Mock ist ein künstliches Objekt, das eine echte Abhängigkeit ersetzt. Eine Abhängigkeit ist einfach eine andere Klasse, die deine eigentliche Klasse braucht, um ihre Arbeit zu erledigen. In Tests ist das hilfreich, weil du dann nicht jedes Mal eine Datenbank starten oder einen echten Webservice ansprechen musst.

Das Ziel ist nicht, möglichst viel zu simulieren. Das Ziel ist, einen klaren und stabilen Unit Test zu schreiben. Ein Unit Test prüft eine kleine, abgegrenzte Einheit deines Codes, meistens genau eine Klasse oder eine Methode. So erkennst du schneller, ob deine Logik sauber funktioniert oder ob ein Fehler aus einer anderen Stelle kommt.

 

Warum du Mockito überhaupt brauchst

Ohne Mockito sind Tests bei vielen Klassen unnötig schwer. Stell dir vor, dein Service fragt einen Wechselkurs bei einem externen Client ab. Ein Client ist hier einfach eine Klasse, die mit einem anderen System kommuniziert. Für einen echten Test gegen dieses System brauchst du Netzwerk, gültige Antworten und im Zweifel eine stabile Testumgebung. Für die eigentliche Fachlogik deiner Methode ist das oft komplett übertrieben.

Mit Mockito ersetzt du diese echte Abhängigkeit durch einen Mock. Diesem Mock kannst du sagen, wie er sich verhalten soll. Dieses festgelegte Verhalten nennt man Stubbing. Wenn du also definierst, dass ein Mock auf einen Methodenaufruf einen bestimmten Wert zurückgeben soll, dann ist das ein Stub.

Zusätzlich kannst du mit Mockito prüfen, ob ein Methodenaufruf wirklich stattgefunden hat. Das nennt sich Verifizieren oder mit Mockito einfach verify. Dadurch testest du nicht nur das Ergebnis, sondern bei Bedarf auch die Zusammenarbeit zwischen zwei Klassen.

Wichtig ist dabei ein sauberer Fokus. Du testest mit Mockito nicht die fremde Bibliothek, nicht die Datenbank und auch nicht das Netzwerk. Du testest deine eigene Logik. Genau deshalb ist Mockito in Java-Projekten zusammen mit JUnit so verbreitet. JUnit ist das Test-Framework, also das Werkzeug, das deine Testmethoden ausführt und dir sagt, ob ein Test grün oder rot ist.

 

Das erste Beispiel mit Mockito

Nehmen wir eine kleine Klasse, die Euro in US-Dollar umrechnet. Der Wechselkurs kommt von einer separaten Klasse namens ExchangeRateClient. Diese Klasse ist die Abhängigkeit unseres Services.

public class PriceService {

    private final ExchangeRateClient exchangeRateClient;

    public PriceService(ExchangeRateClient exchangeRateClient) {
        this.exchangeRateClient = exchangeRateClient;
    }

    public BigDecimal convertEuroToUsd(BigDecimal amountInEuro) {
        BigDecimal rate = exchangeRateClient.currentRate("USD");
        return amountInEuro.multiply(rate);
    }
}

Damit du Mockito in einem Maven-Projekt nutzen kannst, brauchst du die Bibliothek als Test-Abhängigkeit. Maven ist dabei dein Build-Werkzeug, also das Tool, das Abhängigkeiten lädt und dein Projekt baut. Die konkrete Version nimmst du passend zu deinem Projekt.

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>${mockito.version}</version>
    <scope>test</scope>
</dependency>

Der Test dazu sieht so aus:

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.math.BigDecimal;
import org.junit.jupiter.api.Test;

class PriceServiceTest {

    @Test
    void convertsEuroToUsd() {
        ExchangeRateClient client = mock(ExchangeRateClient.class);
        when(client.currentRate("USD")).thenReturn(new BigDecimal("1.10"));

        PriceService service = new PriceService(client);
        BigDecimal result = service.convertEuroToUsd(new BigDecimal("10.00"));

        assertEquals(new BigDecimal("11.0000"), result);
        verify(client).currentRate("USD");
    }
}

Hier passieren ein paar wichtige Dinge. Mit mock(ExchangeRateClient.class) erzeugst du einen Mock der echten Abhängigkeit. Mit when(...).thenReturn(...) definierst du das Stubbing. Du sagst also: Wenn currentRate("USD") aufgerufen wird, gib 1.10 zurück. Danach erzeugst du deinen echten PriceService, gibst ihm aber nicht den echten Client, sondern den Mock.

Mit assertEquals(...) prüfst du das Ergebnis. Das ist eine Assertion, also eine konkrete Überprüfung im Test. Mit verify(client).currentRate("USD") prüfst du zusätzlich, dass der Service den Client wirklich aufgerufen hat.

Genau das ist der Kern von Mockito. Du kontrollierst die Umgebung deiner Klasse so weit, dass du nur noch deine Logik testest. Der Test ist dadurch schnell, nachvollziehbar und unabhängig von äußeren Systemen.

 

Wie du mit komplexeren Fällen sauber umgehst

In echten Projekten hat eine Klasse oft mehr als eine Abhängigkeit. Vielleicht zieht sie Daten aus einem Repository, ruft einen Client auf und schreibt am Ende noch in ein Log. Ein Repository ist meist eine Klasse, die Daten aus einer Datenquelle liest oder speichert. Auch dann bleibt das Prinzip gleich: Deine Klasse unter Test ist echt, ihre Abhängigkeiten sind Mocks.

Komplex wird es meistens nicht wegen Mockito selbst, sondern wegen unklarer Verantwortlichkeiten in der produktiven Klasse. Wenn du beim Schreiben eines Tests plötzlich fünf Mocks brauchst, ist das oft ein Signal, dass die Klasse zu viel Verantwortung hat. Mockito hilft dir dann zwar beim Testen, zeigt dir aber gleichzeitig auch ein mögliches Designproblem.

Ein weiterer typischer Fall sind Fehler-Szenarien. Auch die kannst du mit Mockito sehr gut testen. Dafür lässt du einen Mock gezielt eine Exception werfen. Eine Exception ist ein Fehlerobjekt in Java, das signalisiert, dass etwas schiefgelaufen ist.

when(client.currentRate("USD")).thenThrow(new IllegalStateException("Kein Kurs verfügbar"));

Damit kannst du prüfen, ob deine Klasse sauber auf Fehler reagiert. Zum Beispiel, ob sie eine sinnvolle Exception weitergibt oder einen Fallback nutzt.

Wenn die aufgerufene Methode Parameter bekommt, die für den Test nicht wichtig sind, kannst du mit einem Argument Matcher arbeiten. Ein Argument Matcher ist ein Platzhalter für Methodenparameter. anyString() bedeutet zum Beispiel, dass irgendein String akzeptiert wird.

when(client.currentRate(anyString())).thenReturn(new BigDecimal("1.10"));

Das ist praktisch, sollte aber nicht zu locker eingesetzt werden. Wenn der konkrete Parameter fachlich wichtig ist, dann teste lieber genau diesen Wert. Zu breite Matcher machen Tests schnell unscharf.

Ein häufiger Anfängerfehler ist außerdem, zu viel zu mocken. Einfache Datenobjekte, also zum Beispiel BigDecimal, String oder kleine Fachobjekte ohne externe Abhängigkeiten, solltest du in der Regel nicht mocken. Nimm echte Objekte, wenn sie billig und klar erzeugbar sind. Gemockt werden vor allem Dinge außerhalb deiner eigentlichen Logik, etwa Clients, Repositories oder andere Services.

Für größere Testklassen wirst du später wahrscheinlich noch auf @Mock stoßen. Das ist eine Annotation, also eine Markierung direkt im Code, mit der Mockito Mocks automatisch anlegen kann. Für den Einstieg reicht die Variante mit mock(...) aber völlig aus, weil du damit klarer siehst, was im Test tatsächlich passiert.

 

Fazit

Mockito ist kein Zaubertrick und auch kein Ersatz für gutes Design. Es ist ein sehr praktisches Werkzeug, mit dem du Abhängigkeiten in Tests kontrollierst. Dadurch werden deine Unit Tests schneller, klarer und stabiler. Du legst fest, was ein Mock zurückgeben soll, prüfst das Ergebnis deiner Methode und verifizierst bei Bedarf die Zusammenarbeit mit anderen Klassen.

Für den Einstieg reicht es, drei Dinge sauber zu beherrschen: mock, when(...).thenReturn(...) und verify. Wenn das sitzt, kannst du später gezielt auf Fehlerfälle, Argument Matcher und automatische Mocks mit Annotationen erweitern.

Mein Rat aus der Praxis ist simpel: Halte deine Tests klein, mocke nur echte Abhängigkeiten und prüfe immer das Verhalten, das fachlich wirklich wichtig ist. Dann ist Mockito kein kompliziertes Extra, sondern ein ziemlich direktes Werkzeug, das dir den Testalltag in Java deutlich leichter macht.