Schlangen und Kekse
Seit Jahrtausenden üben Orakel eine magische Anziehungskraft auf die menschliche Fantasie aus. Im antiken Griechenland pilgerten Könige, Feldherren und einfache Bürger nach Delphi, um der berühmten Pythia, der Priesterin des Orakels von Delphi, ihre dringendsten Fragen zu stellen. Die auch "Schlangenpriesterin" genannte Pythia saß über einer mystischen Erdspalte und gab kryptische Prophezeiungen von sich, die das Schicksal ganzer Reiche bestimmen sollten. Könige richteten ihre Kriegsstrategien danach aus, Händler planten ihre Unternehmungen und niemand wagte es, eine wichtige Entscheidung zu treffen, ohne zuvor das Orakel zu konsultieren.
Mehr als 2.000 Jahre später treffen wir auf ein neues Orakel. Nicht in einem antiken Tempel, sondern in einer heruntergekommenen Wohnung im Herzen einer simulierten Realität. In "The Matrix" ist das Orakel eine alte Frau, die Kekse backt und über eine überraschend große Weisheit verfügt. Sie sitzt nicht über einer Erdspalte, sondern am Küchentisch, bietet Kekse an und prophezeit Neo, dass er nicht "The One" sein wird – wobei sie sich natürlich irrt (oder auch nicht, je nachdem, wie wir es sehen wollen). Die alte Frau im Film ist nicht weniger mysteriös als ihr antikes Vorbild, aber statt kryptisch ist sie tröstlich, statt unzugänglich ist sie mütterlich und statt auf spirituelle Kräfte verlässt sie sich auf ihre beeindruckende Fähigkeit, menschliche Emotionen zu durchschauen.
Diese beiden Orakel verbindet etwas Faszinierendes. Sie müssen wissen, was als Nächstes passiert. Sie müssen vorhersehen, was richtig und was falsch ist. Kurz gesagt müssen sie die Wahrheit kennen, auch wenn diese komplex, mehrdeutig oder gar paradox ist.
Test Oracles
Und genau darum geht es in diesem Artikel. In der Softwareentwicklung gibt es nämlich ein modernes Äquivalent zum Orakel von Delphi und zum Orakel aus "The Matrix": das Test Oracle. Dabei handelt es sich nicht um ein mystisches Wesen oder ein weises Programm, sondern um ein Konzept, mit dem wir einer der schwierigsten Fragen der Qualitätssicherung nachgehen: "Ist das Ergebnis dieses Tests korrekt oder nicht?"
Der Begriff "Test Oracle" wurde 1978 von William E. Howden in seiner Arbeit "Theoretical and empirical studies of program testing" geprägt:
In order to use testing to validate a program it is necessary to assume the existence of a test oracle which can be used to check the correctness of test output. The most common kind of test oracle is one which can be used to check the correctness of output values for a given set of input values.
Ein Test Oracle ist im Kern genau wie sein mythologisches Vorbild: ein Verfahren oder eine Quelle, die die "Wahrheit" kennt. Es ist die Instanz, die entscheidet, ob der Test bestanden wurde oder nicht. Und wie die antike Priesterin von Delphi oder die weise Frau in "The Matrix" muss es manchmal kreative, indirekte oder überraschend simple Wege finden, um diese Wahrheit zu offenbaren. Besonders, wenn diese alles andere als offensichtlich ist.
Unit Tests
Bei Unit Tests decken Test Oracles direkte Ausgaben (Rückgabewerte), lokale Nebenwirkungen (Zustandsänderungen) sowie indirekte Ausgaben (an kollaborierende Objekte gesendete Nachrichten) ab. Gute Unit Tests machen deutlich, welche dieser Aspekte überprüft werden.
Rückgabewerte
Das Test Oracle vergleicht bei Funktionen und Methoden ohne Seiteneffekte den tatsächlichen Rückgabewert mit dem erwarteten.
Lokale Seiteneffekte
Viele Objekte ändern ihren eigenen internen Zustand oder den Zustand von Objekten, die als Argumente übergeben wurden. Das Test Oracle überprüft anschließend, ob der Zustand nach der Ausführung den Erwartungen entspricht.
Indirekte Ergebnisse
Wenn ein Objekt mit anderen Objekten zusammenarbeitet (Services, Repositories, Event Buses, Logger usw.), ist das wichtigste beobachtbare Verhalten möglicherweise eher die Art und Weise, wie es mit seinen kollaborierenden Objekten kommuniziert, als das, was es zurückgibt. In diesem Fall geht es beim Test Oracle also um die Kommunikation: Hat das getestete Objekt die richtigen Nachrichten (Methodenaufrufe, Argumente) an seine kollaborierenden Objekte geschickt? Hier kommen Mock Objects ins Spiel.
Es ist wichtig, den Unterschied zwischen der Verwendung eines Test Stubs (um Eingaben von Abhängigkeiten zu kontrollieren) und eines Mock Objects (um Ausgaben an Abhängigkeiten zu überprüfen) zu kennen, um Klarheit zu schaffen. Wenn dir die Interaktionen wichtig sind, sind die Erwartungen deines Mock Objects das Orakel für die Korrektheit dieses Objekts in Bezug auf seine kollaborierenden Objekte.
Integration Tests
Ein Integration Test Oracle überprüft, ob mehrere echte Komponenten richtig zusammenarbeiten und ob ihre technischen Seiteneffekte (Datenbankschreibvorgänge, Nachrichten, Dateien, Netzwerkaufrufe usw.) mit den Versprechen des Systems an dieser Integrationsgrenze übereinstimmen.
Kombiniertes Ergebnis
Sind mehrere Systemteile miteinander verbunden (beispielsweise ein Service, sein Repository und ein externer API-Client), schaut das Test Oracle häufig auf das kombinierte Ergebnis. So wird beispielsweise überprüft, ob ein Service ein DTO zurückgibt, das Daten aus einer echten Datenbanktabelle anzeigt, oder ob ein Query Handler die richtige Projektion zurückgibt, nachdem ein Command Handler Events emittiert hat.
Seiteneffekte der Infrastruktur
Integrationstests nutzen oft Seiteneffekte als primäres Test Oracle:
- Datenbank: Überprüfe nach dem Ausführen eines Befehls, ob die erwarteten Zeilen mit den richtigen Werten in der Datenbank vorhanden sind.
- Dateisystem: Überprüfe, ob eine Datei erstellt, aktualisiert oder gelöscht wurde und ob ihr Inhalt den Erwartungen entspricht.
- Message Queues / Event Buses: Überprüfe, ob eine bestimmte Nachricht verschickt oder ein Event emittiert wurde.
Hier sind Seiteneffekte kein Implementierungsdetail. Sie sind das beobachtbare Verhalten, das für den Test wichtig ist. Das Test Oracle wird als Abfragen an diese externen Systeme ausgedrückt.
Überprüfung der Interaktion auf höherer Ebene
Während Unit Tests in der Regel Mock Objects nutzen, um die Kommunikation zwischen zusammenarbeitenden Objekten genau zu überprüfen, können Integrationstests Interaktionen auf einer gröberen Ebene testen. Beispielsweise kann überprüft werden, ob ein Dienst einen HTTP-Aufruf an ein Test Double einer Drittanbieter-API mit bestimmten Parametern durchgeführt hat.
Grundsätzlich funktioniert das ähnlich wie bei den Unit Tests, die ich in "Testen mit (und ohne) Abhängigkeiten" beschrieben habe. Allerdings auf einer höheren Architekturebene: Wir nutzen ein Stub- oder Mock-Gateway, um Eingaben zu steuern und Ausgaben über Servicegrenzen hinweg zu überprüfen.
End-to-End Tests
Bei End-to-End-Tests wird das System als Black Box betrachtet und geprüft, wie es sich von Anfang bis Ende verhält. Seiteneffekte über Benutzeroberflächen, Datenbanken, Warteschlangen und externe Integrationen sind für das Test Oracle sehr wichtig: Wenn etwas von dem, was erwartet wird, fehlt oder nicht stimmt, gilt der Workflow als nicht gelungen.
Sichtbare Ergebnisse
Diese Test Oracles checken, was die Nutzerin oder der Nutzer sieht:
- Nach dem Checkout-Vorgang im Browser zeigt die Seite "Bestellung aufgegeben" an und zeigt die richtige Bestellübersicht
- Eine PDF-Rechnung hat die richtigen Kundendaten, Einzelposten, Summen und Steuerberechnungen
- Body und HTTP-Status einer API-Antwort passen zum Contract eines komplexen Workflows
Geschäftszustand über Bounded Contexts hinweg
End-to-End-Tests zeigen oft, dass eine Geschäftsaktion richtig im System weitergeleitet wurde:
- Ein neu registrierter Benutzer taucht in der Kundendatenbank auf, hat ein aktiviertes Konto und bekommt Standardrollen zugewiesen
- Nach dem Aufgeben einer Bestellung werden im Bestellkontext Datensätze erstellt, im Lagerkontext Bestände reserviert und ein Zahlungsvorgang erfasst
Hier sind die Seiteneffekte auf mehrere Teilsysteme verteilt. Das Test Oracle ist eine Sammlung von Aussagen über mehrere Datenquellen, die zusammen die "geschäftliche Korrektheit" verkörpern.
Externe Seiteneffekte und Integrationen
Schließlich betrachten End-to-End Test Oracles oft echte Seiteneffekte, die für Nutzerinnen oder externe Partner wichtig sind:
- Eine Bestellbestätigung per E-Mail oder SMS wurde tatsächlich verschickt (und hat den richtigen Inhalt)
- Ein Eintrag im Audit Trail wurde für eine wichtige Aktion erstellt
- Ein Webhook wurde mit der richtigen Payload an ein Partnersystem geschickt
Das Verständnis von Test Oracles ist eine Sache. Die richtige Strategie für dein konkretes Projekt auszuwählen, eine ganz andere. Jedes System hat unterschiedliche Anforderungen, und nicht alle Test Oracles passen zu jeder Situation.
Ich kann dir helfen: Zusammen finden wir die Teststrategie, die wirklich zu deinem Projekt passt, und wählen die Test Oracles aus, die für deine Tests die größte Aussagekraft bringen.
Fazit
Das Verständnis von Test Oracles auf allen drei Ebenen, Unit Tests, Integration Tests und End-to-End Tests, ist für das Schreiben effektiver automatisierter Tests unerlässlich. Jede Ebene beantwortet eine andere Frage zur Korrektheit:
- Unit Tests überprüfen das Verhalten einzelner Objekte und die Kollaboration mehrerer Objekte
- Integration Tests bestätigen, dass mehrere Systemteile zusammenarbeiten und die richtigen Seiteneffekte haben
- End-to-End Tests validieren, dass komplette Workflows echten Business Value liefern
In der Praxis nutzt eine umfassende Testsuite alle drei Ebenen von Tests, wobei jede ihre eigene Strategie für Test Oracles hat, die auf das zugeschnitten ist, was auf dieser Ebene wichtig ist. Egal, ob du einen Rückgabewert überprüfst, eine Objektzusammenarbeit verifizierst, den Datenbankstatus kontrollierst oder eine gesendete E-Mail testest: Du wendest immer das gleiche Grundprinzip an. Verwende ein Test Oracle, um das erwartete Verhalten explizit, beobachtbar und testbar zu machen.
Indem du dir genau überlegst, welche Test Oracles du wählst und was sie bewerten, schaffst du Vertrauen, dass dein System funktioniert. Nicht nur isoliert, sondern als Ganzes, und zwar so, wie es für deine Nutzerinnen und Nutzer wirklich wichtig ist.