Start / Seminare / Java Testing mit JUnit, Mockito und Testcontainers
Modul
Test Doubles und Mockito-Grundlagen
4 Kapitel in diesem Modul-Video · Laufzeit
Transkript
Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.
Test Doubles und Mockito-Grundlagen
0:00 Willkommen zum zweiten Tag. Heute geht es um Mockito — und damit um ein Werkzeug, das leicht zu bedienen und schwer richtig einzusetzen ist. Deshalb möchte ich diesem Tag einen Satz voranstellen, der wie eine Spitzfindigkeit klingt und keine ist: Ein Mock ist kein Werkzeug zum Testen. Ein Mock ist eine Entscheidung darüber, was der Test nicht mehr prüft. Jede Attrappe ist eine bewusst gezogene Grenze.
0:24 Wer sie bewusst zieht, bekommt schnelle und aussagekräftige Tests. Wer sie unbewusst zieht, bekommt eine grüne Testsuite über einer kaputten Anwendung.
Test Doubles und Mockito-Grundlagen
0:33 Der zweite Tag hat vier Module. Wir klären zuerst die Begriffe und die Grundlagen, prüfen dann Interaktionen, steigen ins fortgeschrittene Stubbing ein und enden mit der Frage, wann Mocking zum Architekturproblem wird. Das letzte Modul ist das wichtigste — die drei davor sind seine Voraussetzung.
Test Doubles unterscheiden
0:51 Bevor wir Mockito anfassen, sortieren wir die Begriffe. Es gibt fünf Arten von Attrappen, und im Alltag sagen alle Mock. Genau daher kommt die Hälfte der Missverständnisse. Der Begriff Test Double stammt aus dem Film: der Stuntman, der für den Hauptdarsteller einspringt. Und wie beim Film gibt es Abstufungen. Ein Dummy wird nur übergeben und tut nichts. Ein Stub liefert vorbereitete Antworten.
1:16 Ein Fake ist eine vereinfachte, aber funktionierende Umsetzung — eine Datenbank im Speicher etwa. Ein Spy umhüllt das echte Objekt und protokolliert mit. Und ein Mock ist ein Stub, dessen Aufrufe der Test hinterher prüft. Der Unterschied zwischen Stub und Mock ist also nicht die Technik, sondern die Absicht: Wird nur geantwortet oder auch geprüft?
1:38 Diese vier Felder beantworten die Frage, die vor jedem Mock steht: Muss hier überhaupt etwas ersetzt werden? Oben links die Antwort, die viel zu selten gewählt wird — echt lassen. Rechnende Klassen, Wertobjekte, Sammlungen: schnell, deterministisch, kein Ersatz nötig. Oben rechts der Fake, wenn Sie echtes Verhalten brauchen, die echte Umsetzung aber zu schwer ist.
2:00 Unten links Stub oder Mock, wenn nur Antworten gebraucht werden oder der Aufruf selbst die Aussage ist. Und unten rechts der Container — dazu kommen wir morgen. Vier Felder, vier Antworten, und drei davon werden im Alltag übersprungen. Das ist der Gedanke, den ich Ihnen für den ganzen Tag mitgeben möchte. Jede Attrappe ist eine Annahme über fremdes Verhalten. Sie sagen: Zahlwerk antwortet so.
2:25 Und diese Annahme kann veralten, ohne dass ein Test rot wird — das ist das Unangenehme daran. Was ersetzt wird, prüft der Test nicht mehr, und diese Lücke muss anderswo geschlossen sein. Ein Fake hat hier einen Vorteil: Er gilt über viele Tests und lässt sich gegen das Original prüfen. Ein Stub gilt für genau einen Test.
2:45 Und Wertobjekte, Sammlungen und reine Rechenlogik werden gar nicht ersetzt. Die dritte Spalte ist die eigentliche Entscheidungshilfe. Ein Dummy für Pflichtparameter ohne Bedeutung. Ein Stub für einen einzelnen Lesezugriff. Ein Fake, wenn dieselbe Abhängigkeit in dreißig Tests gebraucht wird — dann lohnt die Investition. Ein Spy für Altcode, der noch keine saubere Schnittstelle hat.
3:08 Und ein Mock genau dann, wenn der Aufruf selbst das erwartete Ergebnis ist. Der Hinweis darunter ist eine gute Prüfung im Alltag: Wenn Sie nicht sagen können, welche dieser fünf Zeilen gemeint ist, brauchen Sie die Attrappe wahrscheinlich gar nicht. Der erste Punkt ist der Reflex, den wir alle kennen: Jede Abhängigkeit wird gemockt, auch die Klasse, die nur rechnet.
3:30 Der zweite ist subtiler — ein Stub wird verifiziert und wird damit still zum Mock; ab da prüft der Test Interna. Der dritte ist der gefährlichste: Ein Fake bildet das echte Verhalten falsch ab. Dann sind alle Tests grün, die ihn berühren, und alle sind wertlos. Und der vierte ist die Lücke, über die wir eben gesprochen haben — die ersetzte Abhängigkeit wird nirgends echt getestet, und niemand merkt es. Deshalb gehört jede Lücke notiert.
Mocks erzeugen und einbinden
3:57 Jetzt zur Praxis. Mockito erzeugen und einbinden ist erfreulich wenig Arbeit — und ein paar Details entscheiden trotzdem darüber, ob es funktioniert. Sie können Mocks von Hand erzeugen, in der Praxis nutzen Sie aber die Annotationen. Dafür braucht es ein eigenes Artefakt, die Jupiter-Integration von Mockito. Die kümmert sich um zwei Dinge: Vor jedem Test werden die annotierten Felder gefüllt, und nach jedem Test prüft sie, ob alles, was Sie vorbereitet haben, auch gebraucht wurde.
4:25 Diese zweite Aufgabe klingt nach Bevormundung und ist eine der nützlichsten Eigenschaften von Mockito — dazu kommen wir im achten Modul ausführlich. Standardmäßig arbeitet die Integration mit strengen Stubs. Dieses Muster werden Sie heute noch oft schreiben. Die Extension an der Klasse, dann die Mocks als Felder, dann der Prüfling.
4:45 Interessant ist die letzte Annotation: Sie füllt den Konstruktor des Prüflings mit den passenden Mocks — Sie müssen die Reihenfolge nicht kennen und nicht pflegen. Das ist bequem und hat eine Kehrseite, die wir gleich sehen. Und noch etwas: Der Prüfling selbst wird nicht gemockt. Das klingt selbstverständlich, passiert aber regelmäßig, wenn Klassen mit ähnlichen Namen im Spiel sind — und dann prüft der Test nur noch sich selbst.
5:10 Vier Annotationen, vier Rollen — und die vierte ist die einzige, die kein Double ist. Wichtig ist die Zeile zum Spy: Dort steckt ein echtes Objekt drin, dessen Aufrufe protokolliert werden. Das ist etwas völlig anderes als ein Mock, auch wenn beide Annotationen nebeneinanderstehen. Der Hinweis in der Fußzeile spart Ihnen die häufigste Fehlersuche des Tages: Sind alle vier Felder null, fehlt entweder die Extension an der Klasse oder das Artefakt im Build.
5:36 Die Fehlermeldung zeigt dann auf eine Zeile mitten im Test — und nicht auf die Ursache. Ein frisch erzeugter Mock antwortet auf alles. Er liefert null für Objekte, null für Zahlen, eine leere Liste für Sammlungen. Das ist gut gemeint und führt zu einem typischen Verlauf: Sie vergessen einen Stub, der Test läuft weiter, und drei Zeilen später scheitert er an einer Nullzeigerausnahme — an einer Stelle, die mit der Ursache nichts zu tun hat.
6:02 Wer die Standardantworten kennt, erkennt das Muster sofort. Es gibt auch andere Voreinstellungen, etwa tief verschachtelte Mocks. Die machen den Test kurz und verschleiern in aller Regel einen fehlenden Stub. Der erste Punkt ist die Kehrseite der Bequemlichkeit: Gibt es mehrere passende Konstruktoren, wählt die Injektion still einen aus — und nicht immer den gemeinten.
6:24 Der zweite betrifft finale Klassen; das geht heute meistens, aber es lohnt zu wissen, warum es geht. Wir kommen im achten Modul darauf zurück. Der dritte ist der bereits erwähnte Selbstbezug — der Prüfling wird gemockt, und der Test prüft nichts mehr. Und der vierte ist die Fehlersuche, die man einmal erlebt haben muss: Die Extension fehlt, alle Felder sind null, und die Meldung zeigt auf die falsche Zeile.
Verhalten definieren
6:48 Kommen wir zum Kern von Mockito: dem Stubbing. Erst legen Sie fest, was zurückkommt — dann prüfen Sie, was Ihr Code damit anstellt. Stubbing ist im Grunde ein Wenn-Dann-Satz: Wenn diese Methode mit diesen Argumenten gerufen wird, gib das zurück. Dafür gibt es zwei Schreibrichtungen. Die übliche beginnt mit when und der Aufruf steht in der Klammer. Die umgekehrte beginnt mit doReturn oder doThrow und nennt den Mock am Ende. Warum zwei?
7:15 Weil die erste Variante die Methode tatsächlich aufruft, um sie zu erkennen. Bei einer Methode ohne Rückgabewert geht das nicht, und bei einem Spy hätte es einen echten Nebeneffekt. Für diese beiden Fälle gibt es die umgekehrte Reihenfolge. Drei Muster in einem Block. Oben der Normalfall. In der Mitte ein Detail, das viele nicht kennen: Zwei Antworten hintereinander beantworten den ersten und den zweiten Aufruf verschieden — ideal, um einen Statuswechsel abzubilden, ohne eine Schleife zu bauen.
7:45 Unten die umgekehrte Schreibweise für eine Methode ohne Rückgabewert. Achten Sie hier auf die Reihenfolge: Erst wird gesagt, was passieren soll, dann an welchem Mock. Das liest sich beim ersten Mal ungewohnt, ist aber technisch notwendig — anders ließe sich die Methode gar nicht erst erfassen. Diese Regel kostet jeden einmal zwanzig Minuten. Sobald ein Argument ein Matcher ist, müssen es alle sein. Ein fester Wert wird dann in eq eingepackt.
8:11 Tun Sie das nicht, bricht Mockito ab — und die Meldung nennt oft eine ganz andere Stelle, weil der Matcher intern schon registriert wurde. Der zweite Teil ist eine inhaltliche Warnung: any passt auf alles und macht den Test unempfindlich. Je genauer der Matcher, desto genauer sagt der rote Test, was sich geändert hat. Ein Test voller any ist bequem geschrieben und sagt wenig aus.
8:35 Hier sehen Sie exakt denselben Test in der verhaltensgetriebenen Schreibweise. Aus when wird given, aus verify wird then und should. Technisch ändert sich nichts. Was sich ändert, ist die Lesart: Der Test folgt sichtbar dem Muster gegeben, wenn, dann. In Teams, die ihre Anforderungen so formulieren, ist das ein echter Gewinn, weil Test und Anforderung dieselbe Form haben.
8:57 Meine einzige Empfehlung dazu: Entscheiden Sie sich im Team für eine Schreibweise. Beide gemischt in einer Klasse ist anstrengender als jede der beiden allein. Der erste Punkt ist die Matcher-Regel, die wir eben besprochen haben — und die irreführende Meldung dazu. Der zweite ist ein Wartungsproblem mit Anlauf: Ein Stub im gemeinsamen Aufbau gilt für alle Tests der Klasse und wird von den wenigsten gebraucht.
9:21 Der dritte ist die Spy-Falle: when auf einem Spy ruft die echte Methode auf, und wenn die etwas speichert oder verschickt, ist es passiert. Und der vierte ist die stille Entwertung — überall any, und der Test bleibt grün, obwohl sich die Argumente längst geändert haben.
Übung
9:36 Jetzt lösen wir Zahlwerk aus dem Bestellabschluss von Krautgut heraus — und notieren dabei, was wir dafür aufgeben. Zahlwerk ist der externe Zahlungsdienst von Krautgut. Er antwortet mit einer Referenz im Format KG und vier Ziffern oder mit einer Ablehnung. Ihre Aufgabe ist, den Bestellabschluss ohne Netzwerkzugriff prüfbar zu machen — in unter einer Sekunde, mit je einem Test für Erfolg, Ablehnung und Zeitüberschreitung.
10:01 Der interessanteste Teil steht im Lernziel: Sie sollen dabei entscheiden, welche Aussage der Test durch die Attrappe verliert. Diese Frage stellt sich im Alltag fast nie, und genau deshalb üben wir sie hier ausdrücklich. Schritt eins ist die wichtigste Weichenstellung, auch wenn er harmlos klingt: die Schnittstelle auf das reduzieren, was Krautgut wirklich ruft.
10:23 Nicht die volle Zahlwerk-API nachbauen — nur den Ausschnitt, den Ihre Anwendung braucht. Danach kommen die drei Fälle, jeder als eigener Test. Und Schritt vier ist die Eintrittskarte für den dritten Tag: Notieren Sie, welche Aussage über Zahlwerk dieser Test nicht mehr trifft. Im zwölften Modul schließen wir genau diese Lücke — dann bekommt Zahlwerk eine echte HTTP-Gegenstelle im Container.
10:47 Der erste Punkt ist die Bequemlichkeit, die den Test entwertet: any für jedes Argument, und der Betrag wird nie geprüft. Gerade beim Zahlungsdienst ist das die eine Sache, die wirklich stimmen muss. Der zweite ist die Zusammenlegung aller drei Fälle in einen Test. Der dritte ist ein Anfängerfehler mit spürbarer Folge: Die Zeitüberschreitung wird mit einer echten Wartezeit nachgestellt — ein Test, der drei Sekunden schläft, wird bald aus der Pipeline genommen.
11:13 Und der vierte ist das Überspringen von Schritt vier. Die Lücke bleibt, sie fällt nur später auf.
Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →