Unit-Tests sind einfach zu schreiben und schnell auszuführen. Produktion ahmt perfekt kontrollierte Umgebungen überhaupt nicht nach. Die Lücke zwischen ihnen—Integrationstests—ist, wo die meisten Teams kämpfen.
Warum Integrationstests scheitern
Bevor Sie Ihre Tests reparieren, verstehen Sie, warum sie kaputt sind:
Umgebungsunterschiede
Ihre Test-Datenbank ist nicht Ihre Produktionsdatenbank. Ihre Test-Message-Queue hat nicht die gleichen Race Conditions. Ihr Test-Netzwerk hat nicht die gleiche Latenz. Diese Unterschiede verbergen Bugs.
State Management
Integrationstests erzeugen State. Nachfolgende Tests hängen von diesem State ab—oder scheitern deswegen. Tests, die einzeln bestehen, scheitern, wenn sie zusammen laufen. Tests, die lokal bestehen, scheitern in CI.
Timing-Abhängigkeiten
Integrationen involvieren Netzwerkaufrufe. Netzwerkaufrufe brauchen variable Zeit. Tests, die diese Variabilität nicht berücksichtigen, werden flaky.
Zuverlässige Integrationstests bauen
1. Testdaten isolieren
Jeder Test sollte seine eigenen Daten erstellen und danach aufräumen:
- Verwenden Sie Transaktionen, die nach jedem Test zurückrollen
- Generieren Sie eindeutige Identifikatoren für Testdaten
- Hängen Sie niemals von vorhandenen Daten ab
- Hinterlassen Sie niemals Testdaten
2. Testcontainers verwenden
Starten Sie echte Abhängigkeiten in Containern. Ihre Tests laufen gegen echtes PostgreSQL, echtes Kafka, echtes Redis—nicht Mocks, die sich anders verhalten als Produktion.
const postgres = await new PostgreSqlContainer().start();
const connection = await createConnection(postgres.getConnectionUri());
3. Korrektes Warten implementieren
Verwenden Sie nicht sleep(). Es ist entweder zu kurz (flaky) oder zu lang (langsam). Verwenden Sie Polling mit Timeouts:
- Warten Sie auf spezifische Bedingungen, nicht willkürliche Zeit
- Setzen Sie vernünftige Timeouts (schnell scheitern, aber nicht zu schnell)
- Fügen Sie aussagekräftige Fehlermeldungen hinzu, wenn Timeouts auftreten
4. Testen Sie den Vertrag, nicht die Implementierung
Ihre Integrationstests sollten verifizieren, dass Systeme korrekt kommunizieren, nicht wie sie intern funktionieren. Das macht Tests stabiler, wenn sich Implementierungen entwickeln.
Die Testpyramide für Integrationen
Contract Tests (Viele)
Verifizieren Sie, dass Services ihre API-Verträge einhalten. Tools wie Pact lassen Sie Erwartungen definieren und beide Seiten unabhängig verifizieren. Schnell, fokussiert, fangen die meisten Integrationsprobleme.
Component Tests (Einige)
Testen Sie Ihren Service mit echten Abhängigkeiten, aber isoliert von anderen Services. Testcontainers glänzen hier. Langsamer als Contract Tests, aber fangen mehr Probleme.
End-to-End Tests (Wenige)
Volle Systemtests mit allen laufenden Services. Am langsamsten und teuersten, aber fangen Probleme, die nichts anderes findet. Halten Sie diese minimal und auf kritische Pfade fokussiert.
Das Ziel ist nicht, alles auf Integrationsebene zu testen—es ist, die richtigen Dinge auf der richtigen Ebene zu testen.
Externe Abhängigkeiten handhaben
Sie können Third-Party-APIs nicht kontrollieren. Optionen:
- Sandbox-Umgebungen: Nutzen Sie Vendor-Testumgebungen, wenn verfügbar
- Service-Virtualisierung: Aufzeichnen und Abspielen echter API-Antworten
- Contract Testing: Verifizieren Sie, dass Ihre Erwartungen mit deren Dokumentation übereinstimmen
- Failure Injection: Testen Sie, wie Sie deren Ausfälle handhaben
CI/CD-Integration
Integrationstests in CI erfordern Sorgfalt:
- Führen Sie sie in isolierten Umgebungen aus (keine geteilten Datenbanken zwischen Builds)
- Parallelisieren Sie vorsichtig (vermeiden Sie Port-Konflikte, Ressourcen-Kontention)
- Implementieren Sie Retry-Logik für wirklich flaky externe Abhängigkeiten
- Verfolgen Sie Testdauer und Stabilität über Zeit
- Quarantänisieren Sie flaky Tests, statt Fehler zu ignorieren
Erfolg messen
Gute Integrationstests haben diese Eigenschaften:
- Deterministisch: Gleicher Code produziert gleiches Ergebnis, jedes Mal
- Unabhängig: Tests beeinflussen sich nicht gegenseitig
- Schnell genug: Minuten, nicht Stunden
- Aussagekräftig: Fehlschläge zeigen echte Probleme an
- Gepflegt: Tests werden aktualisiert, wenn Systeme sich ändern
Integrationstests sind nicht glamourös, aber sie sind der Unterschied zwischen Vertrauen und Angst beim Deployment in Produktion. Investieren Sie die Zeit, es richtig zu machen.
