Start / Seminare / Java Testing mit JUnit, Mockito und Testcontainers
Modul
Interaktionen und Zusammenarbeit prüfen
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.
Interaktionen und Zusammenarbeit prüfen
0:00 In diesem Modul geht es um die Verifikation — also darum, zu prüfen, ob ein Mock in bestimmter Weise aufgerufen wurde. Und das ist ein zweischneidiges Werkzeug. Auf der einen Seite ist es die einzige Möglichkeit, einen Nebeneffekt zu prüfen: Wenn eine Zahlung ausgelöst wird, gibt es kein Ergebnis, das man vergleichen könnte.
0:19 Auf der anderen Seite ist es der schnellste Weg, einen Test an die Implementierung zu ketten. Wir sehen uns beide Seiten an — und vor allem die Frage, wann Verifikation die richtige Wahl ist und wann nicht.
Interaktionen und Zusammenarbeit prüfen
0:31 Zweites Modul des Mockito-Tages. Wir prüfen zuerst Aufrufe, fangen dann Argumente ein und schließen mit der Frage nach dem rechten Maß. Das letzte Kapitel ist die inhaltliche Brücke zum vierten Modul dieses Tages, in dem es um Testarchitektur geht.
Aufrufe verifizieren
0:47 Beginnen wir mit dem Fall, in dem Verifikation unstrittig richtig ist: wenn das Ergebnis der Aufruf selbst ist. Denken Sie an einen Brief, den Ihre Anwendung abschickt. Sie können nicht prüfen, was zurückkommt — es kommt nichts zurück. Sie können nur prüfen, ob der Brief eingeworfen wurde und was darauf stand. Genau das leistet die Verifikation.
1:08 Sie ist deshalb dort richtig, wo eine Handlung keinen prüfbaren Rückgabewert hat: eine Belastung wird ausgelöst, eine Nachricht verschickt, ein Bestand reserviert. Eine praktische Kleinigkeit, die man wissen sollte: Ohne weitere Angabe erwartet Mockito genau einen Aufruf. Nicht mindestens einen — genau einen. Vier Zeilen, vier verschiedene Aussagen. Die erste prüft einen Aufruf mit konkreten Argumenten.
1:33 Die zweite prüft, dass etwas nicht passiert ist — das ist oft die wertvollere Aussage, gerade beim Stornieren. Die dritte erlaubt mehrere Aufrufe. Und darunter die Reihenfolge: Reserviert wird vor der Belastung. Das ist keine technische Marotte, sondern eine fachliche Regel — sonst zahlt der Kunde für eine Kiste, die es nicht mehr gibt.
1:54 Genau diese Begründung sollten Sie parat haben, wenn Sie eine Reihenfolge prüfen. Fällt sie Ihnen nicht ein, prüfen Sie besser keine. Die Logik dieser Tabelle ist eine Skala von exakt bis großzügig. Ganz oben der Standardfall, ein Aufruf. Darunter die exakte Anzahl, dann die Null, dann Unter- und Obergrenzen. Und ganz unten die schärfste Variante: dieser Aufruf und kein anderer auf dem Mock.
2:18 Der Hinweis in der Fußzeile ist eine Stilfrage mit Substanz: Die ausgeschriebene Form für genau einen Aufruf sagt nichts zusätzlich aus, sie ist nur länger. Interessanter ist die Null-Variante — sie dokumentiert eine Regel, die man sonst nirgends im Code sieht. Hier trennt sich nützliche von schädlicher Verifikation. Eine geprüfte Reihenfolge, die fachlich gar nicht gilt, ist eine Zeitbombe: Sie bricht beim nächsten Refactoring, ohne dass sich das Verhalten geändert hat.
2:47 Technisch praktisch ist, dass die Reihenfolgeprüfung nur die genannten Aufrufe betrachtet — dazwischen darf anderes passieren. Fachliche Reihenfolgen sind übrigens selten. Aber wenn es sie gibt, sind sie meistens wichtig, weil sie Geld oder Bestände betreffen. Meine Empfehlung: Wer eine Reihenfolge prüft, sollte im Test in einem Satz benennen können, welche Regel dahintersteht.
3:10 Der erste Punkt beschreibt den überspezifizierten Test: Jeder Aufruf wird verifiziert, und der Test beschreibt die Implementierung Zeile für Zeile. Der zweite ist heimtückisch — eine Nicht-Aufruf-Prüfung auf eine Methode, die es gar nicht mehr gibt, bleibt grün und sichert nichts. Der dritte ist die eben besprochene zufällige Reihenfolge.
3:29 Und der vierte ist die doppelte Prüfung: Verifiziert wird ein Aufruf, dessen Wirkung schon durch den Rückgabewert abgedeckt war. Das kostet nichts an Laufzeit, aber es kostet beim nächsten Umbau — dann werden zwei Stellen rot statt einer.
Argumente erfassen und prüfen
3:44 Die spannendere Frage ist selten, ob aufgerufen wurde. Sie lautet: womit? Und dafür gibt es zwei Werkzeuge. Ein ArgumentCaptor ist im Grunde ein Fangnetz. Er steht am Mock, fängt das tatsächlich übergebene Argument ein und stellt es Ihnen danach für Assertions zur Verfügung. Gebraucht wird er dort, wo das Argument erst im Prüfling entsteht — eine erzeugte Referenz, ein Zeitstempel, ein zusammengesetztes Objekt.
4:11 Sie können es also gar nicht vorher hinschreiben. Seit Mockito 5.3 gibt es dafür eine zweite, kompaktere Variante: eine Prüfung direkt im Matcher. Beide haben ihre Berechtigung, und der Unterschied liegt weniger in der Technik als in der Lesbarkeit. Oben das Fangnetz: erst deklarieren, dann beim Verifizieren einfangen, dann prüfen. Unten die kompakte Variante, bei der die Prüfung direkt im Matcher steht.
4:36 Der Unterschied in der Praxis: Die kompakte Form spart drei Zeilen und liest sich flüssig, solange es einen Aufruf gibt. Bei mehreren Aufrufen bleibt der Captor die bessere Wahl, denn er sammelt alle Argumente in der Reihenfolge ihres Auftretens. Beachten Sie außerdem die Reihenfolge im oberen Block: Erst wird verifiziert und dabei eingefangen, danach geprüft. Wer vorher auswertet, bekommt ein leeres Netz.
5:01 Ein Matcher nimmt eine Bedingung und macht daraus eine wiederverwendbare Prüfung. Der Gewinn liegt nicht in der Technik, sondern in der Sprache: Statt einer Bedingung mit Klammern und Vergleichen steht im Test ein Name, der die Regel benennt. Und im Fehlerfall zeigt Mockito, welche Argumente tatsächlich ankamen — das ist bei der Fehlersuche Gold wert.
5:20 Der letzte Punkt ist die übliche Abwägung: Bedingungen, die sich in vielen Tests wiederholen, gehören in eine benannte Methode. Einmalige Bedingungen dürfen ruhig an Ort und Stelle stehen bleiben. Vier Situationen, vier Antworten — und die Reihenfolge ist auch eine Reihenfolge des Aufwands. Ist das Argument ein bekannter Wert, schreiben Sie ihn einfach hin; alles andere wäre Umweg. Entsteht es erst im Prüfling, brauchen Sie Captor oder Matcher-Prüfung.
5:47 Geht es um mehrere Aufrufe, liefert der Captor alle Werte in Aufrufreihenfolge — damit lässt sich sogar eine Abfolge prüfen, etwa erst Reservierung, dann Nachbestellung. Und wiederkehrende Bedingungen bekommen einen eigenen Matcher. Der Fehler, der hier am häufigsten passiert, steht in Zeile eins: ein Captor für einen Wert, den man einfach hätte hinschreiben können.
6:09 Der erste Punkt ist das leere Netz — der Captor wird vor dem Aufruf ausgewertet. Der zweite ist tückisch, weil der Test grün bleibt: Bei mehreren Aufrufen liefert die einfache Abfrage nur den letzten Wert, und die interessante Abweichung war vielleicht der erste. Der dritte betrifft eigene Matcher: Sie sollen eine Bedingung prüfen und true oder false liefern — steckt eine Assertion darin, scheitert der Vergleich an einer Stelle, an der Mockito noch gar nicht prüft.
6:35 Und der vierte ist ein Klassiker: Das eingefangene Objekt wird als Ganzes verglichen, inklusive Zeitstempel. Dann ist der Test morgen rot.
Maß halten bei der Verifikation
6:44 Und damit zur wichtigsten Frage dieses Moduls. Es gibt zwei Wege, dasselbe zu prüfen — und einer davon altert deutlich schneller. Zustandsprüfung heißt: Ich schaue mir nach der Handlung an, wie die Welt aussieht. Verhaltensprüfung heißt: Ich schaue mir an, was während der Handlung passiert ist. Beide sind legitim, aber sie sind nicht gleichwertig. Der Zustand ist die fachliche Aussage — die Bestellung ist bezahlt.
7:10 Der Aufruf ist die technische — es wurde eine Belastung ausgelöst. Wo beides möglich ist, gewinnt der Zustand, weil er weniger über den Weg behauptet. Die Verhaltensprüfung bleibt für die Fälle, in denen es keinen sichtbaren Zustand gibt. Diese Gegenüberstellung fasst zusammen, warum die Wahl langfristig wichtig ist. Links das Ergebnis, rechts der Weg dorthin.
7:33 Links überlebt der Test Refactorings, rechts bricht er bei Umbauten. Aber lesen Sie auch die dritte Zeile — sie nennt den Preis der linken Spalte: Es braucht einen sichtbaren Zustand. Wenn eine Klasse nichts nach außen zeigt, bleibt nur die rechte Spalte. Das ist übrigens ein guter Hinweis auf einen ungünstigen Schnitt. Anwendungsfälle, die nichts zurückgeben und nur Nebeneffekte auslösen, sind schwer zu prüfen und meistens auch schwer zu verstehen.
8:00 Das ist eine steile These und ich meine sie ernst. Ein fehlender Test lässt einen Fehler durch — das ist schlecht und begrenzt. Ein überspezifizierter Test verbietet jede Umstrukturierung — und das wirkt jeden Tag. Besonders wirksam in dieser Hinsicht ist die Prüfung, dass es keine weiteren Interaktionen gab: Ab dann macht jede neue Zeile Produktionscode einen Test rot, auch wenn sie fachlich nichts ändert.
8:23 Wenn ein Team Refactorings fürchtet, hat es meistens keine Testsuite, sondern eine Zementschicht. Die richtige Frage lautet nicht, ob der Aufruf passierte, sondern ob er passieren musste. Vier konkrete Fälle aus Krautgut, und zwei davon sind ein Nein. Die Belastung bei Zahlwerk wird verifiziert — das ist der Nebeneffekt, den der Kunde merkt.
8:44 Die Preisabfrage nicht, denn wenn der Preis stimmt, wurde offensichtlich gerechnet. Die Log-Ausgabe nicht, denn sie ist kein fachliches Verhalten. Und die Reihenfolge nur, wenn sie wirklich eine Regel ist. Die Faustregel in der Fußzeile funktioniert erstaunlich gut im Alltag: Verifiziert wird, was der Nutzer merken würde, wenn es ausbliebe. Alles andere ist Implementierungsdetail.
9:08 Der erste Punkt haben wir eben besprochen — die Prüfung auf keine weiteren Interaktionen als Gewohnheit in jedem Test. Der zweite ist eine verpasste Gelegenheit: Der Rückgabewert liegt vor, wird aber ignoriert, und stattdessen wird der Aufruf geprüft. Der dritte betrifft lesende Aufrufe; sie zu verifizieren bindet den Test an die Reihenfolge der Abfragen, und die ändert sich beim nächsten Umbau.
9:31 Und der vierte ist der stillste: Eine Verifikation ersetzt die fehlende Assertion. Der Test prüft dann, dass etwas gerufen wurde — aber nicht, dass das Ergebnis stimmt.
Übung
9:41 In der Übung prüfen wir, was Krautgut tatsächlich an Zahlwerk übergibt — und räumen anschließend auf. Die Referenz von Krautgut setzt sich aus dem Präfix KG und der Bestellnummer zusammen. Ihre Aufgabe hat zwei Teile: Zuerst sichern Sie Betrag, Referenzformat und die Reihenfolge von Reservierung und Belastung ab. Dann kommt der ungewöhnlichere Teil — Sie gehen jede vorhandene Verifikation durch und begründen sie.
10:07 Das Erfolgskriterium verlangt ausdrücklich, dass jede verbleibende Verifikation im Test begründet ist. Diese Übung fühlt sich beim zweiten Teil unangenehm an, weil man Tests entfernt. Genau das ist der Punkt: Weniger Verifikationen sind hier ein besseres Ergebnis. Die ersten drei Schritte sind Handwerk: einfangen und prüfen, dieselbe Prüfung kompakt schreiben und beide vergleichen, dann die Reihenfolge absichern.
10:32 Der Vergleich in Schritt zwei ist Absicht — Sie sollen ein Gefühl dafür bekommen, wann welche Form die lesbarere ist. Schritt vier und fünf sind die eigentliche Übung: aufräumen und begründen. Und der Hinweis in der Fußzeile ist die Kontrollfrage — wenn Ihnen für eine Verifikation kein Satz einfällt, der eine Regel benennt, dann haben Sie sie in Schritt vier übersehen.
10:53 Solche Sätze notiert man am besten sofort. Der erste Punkt ist ein technischer: Der Captor wird als Feld deklariert, aber ohne die Extension bleibt er null. Der zweite ist die Reihenfolge ohne fachliche Regel, die wir heute mehrfach hatten. Der dritte ist die Gefahr beim Aufräumen — es fällt ausgerechnet die Verifikation weg, die den einzigen echten Nebeneffekt absicherte.
11:15 Gehen Sie deshalb einzeln vor und nicht in einem Rutsch. Und der vierte ist menschlich: Die Begründungen werden nachträglich erfunden statt beim Schreiben notiert. Nachträglich findet man für fast alles eine Begründung — das ist ja das Problem.
Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →