Komponententests: Testfälle und Isolation verstehen
Ein Komponententest prüft einen abgegrenzten Softwarebaustein gegen erwartete Ergebnisse, möglichst ohne störende Einflüsse anderer Bausteine. So kannst du Fehler früh eingrenzen. Ein bestandener Test bestätigt bei korrektem Testaufbau nur das geprüfte Verhalten in den gewählten Testfällen. Er beweist keine allgemeine Fehlerfreiheit.
Hake ab, was du schon kannst — und komm am Ende hierher zurück!
Was genau wird beim Komponententest geprüft?
Die Softwarebeispiele und Aufgaben in diesem Artikel sind fiktiv. Eine Funktion ist ein benannter Programmteil, den du mit Eingaben aufrufen kannst und der zum Beispiel ein Ergebnis zurückgibt. Stell dir eine Funktion vor, die aus einem Warenwert die Versandkosten berechnet. Du möchtest wissen, ob diese eine Berechnung richtig arbeitet – unabhängig von Benutzeroberfläche, Datenbank und Zahlungsdienst.
Komponententest
Ein Komponententest prüft eine einzelne, abgegrenzte Komponente anhand festgelegter Anforderungen. Dazu wird ein Ausgangszustand hergestellt, die Komponente mit bestimmten Eingaben ausgeführt und das beobachtete Ist-Ergebnis mit einem erwarteten Soll-Ergebnis verglichen.
Was als Komponente gilt, hängt vom Projekt ab. In einem Softwareprojekt kann es eine Funktion, Methode, Klasse oder ein Modul sein. Eine Methode ist eine Funktion, die zu einer Klasse gehört. Eine Klasse beschreibt den Aufbau und das Verhalten gleichartiger Objekte; ein Modul fasst zusammengehörigen Programmcode zusammen. In einem technischen System kann eine Komponente auch Mechanik, Elektronik und Software enthalten. Vor dem Test muss deshalb klar festgelegt sein, wo die Grenze des Prüfgegenstands verläuft.
In vielen Softwarekontexten werden Unit-Test, Modultest und Komponententest ähnlich oder sogar gleichbedeutend verwendet. „Unit“ betont meist eine kleine Codeeinheit. „Komponente“ kann je nach vereinbarter Grenze weiter gefasst sein. Entscheidend ist nicht das Wort allein, sondern was isoliert geprüft wird.
Für einen Komponententest legst du die Grenze und das Prüfziel fest: Was gehört zum Prüfgegenstand, was ist eine Abhängigkeit und welches Verhalten wird erwartet?
Teststufen sicher unterscheiden
Eine Schnittstelle legt fest, wie Programmteile Daten austauschen oder einander aufrufen. Die Teststufen unterscheiden sich vor allem durch Prüfgegenstand und Frage:
| Teststufe | Prüfgegenstand | Leitfrage |
|---|---|---|
| Unit- oder Komponententest | eine abgegrenzte Einheit, meist isoliert | Erfüllt dieser Baustein seine festgelegten Anforderungen? |
| Integrationstest | mehrere integrierte Komponenten oder Dienste im Zusammenspiel | Funktionieren Schnittstellen und Datenaustausch zusammen? |
| Systemtest | das integrierte Gesamtsystem | Erfüllt das gesamte System die festgelegten Systemanforderungen? |
Ein Beispiel zeigt den Fokuswechsel:
- Ein Komponententest prüft, ob
berechneVersandkosten(49)den festgelegten Betrag liefert. - Ein Integrationstest prüft, ob Warenkorb und Versanddienst die Daten im richtigen Format austauschen.
- Ein Systemtest prüft den vollständigen Bestellablauf im integrierten System.
Die Stufen ersetzen einander nicht. Ein korrekter einzelner Baustein kann über eine fehlerhafte Schnittstelle falsch eingebunden sein. Umgekehrt kann ein Systemtest einen Fehler zeigen, ohne seine Ursache so genau einzugrenzen wie ein Komponententest.
Einen aussagekräftigen Testfall entwerfen
Ein Testfall beginnt bei einer Anforderung, also einer Vorgabe für das gewünschte Verhalten. Die Spezifikation hält solche Vorgaben fest. Für unser fiktives Beispiel lautet sie:
rabatt(preis, mitglied) gibt für Mitglieder 10 Prozent des nicht negativen Preises als Rabatt zurück. Für Nichtmitglieder beträgt der Rabatt 0. Negative Preise werden durch die Fehlermeldung „Preis ungültig“ abgewiesen, ohne einen Rabatt zurückzugeben.
Bei rabatt(80, wahr) heißt die Funktion rabatt. Die Werte in Klammern sind ihre Eingaben: der Preis 80 und die Mitgliedschaft. wahr bedeutet „ist Mitglied“, falsch bedeutet „ist kein Mitglied“. Preise und Rabatte verwenden dieselbe Geldeinheit; eine konkrete Programmiersprache brauchst du für das Beispiel nicht.
Gehe in drei Schritten vor:
- Ausgangszustand und Eingaben festlegen: Welche Werte und Voraussetzungen gelten?
- Operation ausführen: Welche Komponente wird aufgerufen?
- Soll und Ist vergleichen: Welches beobachtbare Ergebnis fordert die Spezifikation?
Für den Normalfall preis = 80 und mitglied = wahr berechnest du zuerst den Sollwert: 10 Prozent sind 10 von 100, also ein Zehntel. Du rechnest 80 · 10 / 100 = 8 und erwartest einen Rabatt von 8. Der Test richtet die Eingaben ein, ruft rabatt(80, wahr) auf und vergleicht das Ergebnis mit 8. Liefert die Funktion 8, ist genau dieser Testfall bestanden.
Der entscheidende Gedanke: Der Sollwert stammt aus der Anforderung und wird vor der Auswertung festgelegt. Das Ergebnis der Funktion darf nicht nachträglich zum erwarteten Wert erklärt werden.
Ein einzelner Normalfall reicht nicht. Wähle Testfälle mit unterschiedlichen Aufgaben:
- Normalfall: ein typischer gültiger Wert, etwa
80und Mitglied. - Randfall: ein Wert an einer bedeutsamen Grenze, hier
0und Mitglied; erwartet wird0. - Alternative gültige Bedingung:
80und kein Mitglied; erwartet wird0. - Ungültiger Fall: ein negativer Preis; erwartet wird die in der Spezifikation festgelegte Abweisung.
Eine große Anzahl beliebiger Testwerte ist nicht automatisch aussagekräftig. Gute Testfälle stehen für unterschiedliche Anforderungen, Grenzen und mögliche Fehler. Wie umfassend du Anforderungen und Programmabläufe abdecken musst, hängt vom Projekt und den möglichen Folgen eines Fehlers ab.
Abhängigkeiten kontrollieren und Isolation verstehen
Viele Komponenten rufen andere Teile auf: eine Datenbank, einen Dienst, eine Uhr oder eine Hardware-Schnittstelle. Würdest du alle echten Abhängigkeiten einbinden, könnte ein Fehler außerhalb des Prüfgegenstands den Test beeinflussen. Dann wäre die Ursache schwerer zu erkennen.
Eine Abhängigkeit ist hier ein anderer Teil, den die Komponente benötigt. Für einen isolierten Komponententest ersetzt du solche Teile bei Bedarf durch Testdoubles, also eigens für den Test eingesetzte Ersatzobjekte. Sie liefern kontrollierte Antworten oder zeichnen Aufrufe auf.
Stub und Driver
Ein Stub ersetzt einen Baustein, den die getestete Komponente aufruft, und liefert vorbereitete Antworten. Ein Driver ersetzt den aufrufenden Teil und startet die zu testende Operation mit festgelegten Eingaben.
Eine Komponente zeigeWetter fragt normalerweise einen Wetterdienst ab. Für ihren Komponententest liefert ein Stub immer die kontrollierte Antwort „18 Grad“. So prüfst du, ob zeigeWetter diese Antwort richtig verarbeitet, auch wenn der echte Dienst nicht verfügbar ist.
Damit hast du jedoch noch nicht geprüft, ob die echte Verbindung, das echte Datenformat und mögliche Netzwerkfehler korrekt behandelt werden. Dafür brauchst du passende Integrations- oder weiterführende Tests.
Ein Testdouble ist selbst nur ein Modell. Bildet es Antwortcodes, Plausibilitätsprüfungen oder Zustände unvollständig ab, kann der Test trotz eines späteren Integrationsfehlers grün sein. Außerdem können Test und Implementierung denselben falschen Denkfehler enthalten.
Isolation macht Ursachen leichter sichtbar, blendet aber bewusst einen Teil der Wirklichkeit aus. Deshalb brauchst du ergänzende Teststufen, die das Zusammenspiel prüfen. Sie können während der Entwicklung auch zeitlich parallel zu Komponententests stattfinden.
Fehler auswerten und Korrekturen absichern
Ein fehlgeschlagener Test zeigt zunächst eine Abweichung zwischen Soll und Ist. Er sagt noch nicht automatisch, welche Codezeile die Ursache ist.
Gehe systematisch vor:
- Prüfe, ob Anforderung, Eingaben und Sollwert eindeutig sind.
- Stelle sicher, dass der Testaufbau nicht selbst fehlerhaft ist.
- Verfolge die Verarbeitung bis zur ersten falschen Zustandsänderung oder Ausgabe.
- Behebe die ermittelte Ursache, je nach Befund in der Komponente oder im Testaufbau.
- Führe den fehlgeschlagenen Test und die übrigen passenden Tests erneut aus.
- Bewahre passende Tests auf und führe sie bei späteren Änderungen wieder aus.
Ein Wiederholungstest nach Fehlerbehebung prüft, ob die konkrete Korrektur wirkt. Regressionstests suchen nach unbeabsichtigten Verschlechterungen durch eine Änderung. Dazu gehört sowohl das erneute Auftreten eines bekannten Fehlers als auch die Beschädigung anderer zuvor funktionierender Abläufe.
Für rabatt(80, wahr) lautet das Soll 8, das Ist aber 72. Beim Nachverfolgen der Berechnung findest du im fiktiven Beispiel: Die Funktion berechnet 80 - 8 = 72 und gibt damit den Restbetrag statt des Rabatts zurück. Allein aus dem Istwert 72 wäre diese Ursache noch nicht sicher bewiesen. Nach der Korrektur wird derselbe Test erneut ausgeführt. Besteht er nun, belegt das die Korrektur für diesen Fall; weitere passende Testfälle helfen zu erkennen, ob die Änderung anderes Verhalten beschädigt hat.
Auch Testcode ist Code. Er kann falsche Erwartungen, ungeeignete Daten oder problematische gemeinsame Zustände enthalten und sollte deshalb nachvollziehbar benannt, gepflegt und überprüft werden.
Karteikasten
Überlege zuerst selbst und drehe die Karte anschließend zum Prüfen um.
Alles auf einen Blick
- Komponententest
- Prüfgegenstand
- abgegrenzte Komponente
- beobachtbares Verhalten
- Testfall
- Ausgangszustand und Eingabe
- Soll-Ist-Vergleich
- Normal-, Rand- und Fehlerfall
- Isolation
- kontrollierte Abhängigkeiten
- Stub oder Driver
- begrenztes Modell der Wirklichkeit
- Teststufen
- Unit oder Komponente
- Integration der Teile
- Gesamtsystem
- Ergebnis
- Fehler eingrenzen
- Korrektur wiederholen
- keine Garantie auf Fehlerfreiheit
- Prüfgegenstand
Mit Google fortfahren