🔗 Integration Testing
Integration Tests sind die Mittelstufe zwischen Unit Tests und End-to-End Tests.
Sie prüfen das Zusammenspiel mehrerer Komponenten in einer realitätsnahen, aber kontrollierten Umgebung – ohne das gesamte System in voller Breite zu benötigen.
Integration Tests sind oft die schwierigste Teststufe, weil sie eine klare Abgrenzung erfordern:
Unit Tests prüfen Logik isoliert.
Integration Tests prüfen Zusammenspiel gezielt.
E2E Tests prüfen vollständige Flows im deployed System.
1. Ziel und Einordnung
1.1 Was sind Integration Tests?
Integration Tests prüfen die Zusammenarbeit von mindestens zwei Komponenten über eine echte Schnittstelle.
Typische Formen:
- Service ↔ Datenbank (Repository/DAO gegen echte DB)
- API ↔ Service Layer (HTTP gegen echten Controller, DB evtl. echt)
- Service ↔ Message Broker (Publish/Consume mit Test-Broker)
- Frontend ↔ Backend (Contract/Stub, aber echter HTTP)
Charakteristika:
- Teilweise echte Infrastruktur (z. B. DB, HTTP, Broker)
- Fokus auf Schnittstellen, Konfiguration, Datenflüsse
- Schnell genug für CI, aber deutlich langsamer als Unit Tests
- Weniger breit als E2E, aber näher an der Realität als Unit
1.2 Wofür sind Integration Tests da?
Integration Tests dienen der:
- Absicherung kritischer Integrationspunkte (API, DB, Messaging)
- Früherkennung von Contract-/Schema-Problemen
- Validierung von Konfiguration und Mappings
- Absicherung von Transaktionen und Persistenzlogik
- Reduktion von E2E-Komplexität (E2E wird dadurch kleiner und stabiler)
1.3 Was sind Integration Tests nicht?
Integration Tests sind:
- kein Ersatz für Unit Tests (zu langsam, zu teuer)
- kein Ersatz für E2E (zu wenig Realwelt-Varianz)
- keine “Unit Tests mit echten Frameworks”
- kein Ort für UI-Details
Ein Integration Test ist gezielt, nicht “alles einmal durchklicken”.
2. Die häufigste Verwirrung (und eine klare Regel)
Viele Teams nennen Tests falsch:
- “Unit Tests”, die eigentlich DB/HTTP/Broker nutzen → Integration Tests
- “Integration Tests”, die komplette User Journeys fahren → E2E Tests
Die Abgrenzung wird einfach, wenn du dir diese eine Frage stellst:
Wird echte Infrastruktur genutzt (DB, HTTP, Broker, Filesystem)?
- Wenn nein → Unit Test
- Wenn ja, aber nur ein Integrationspunkt gezielt → Integration Test
- Wenn ja, und mehrere Systeme/Flows übergreifend → E2E Test
3. Test-Mindset
3.1 Teste Integrationsrisiken, nicht Logik
Integration Tests sind primär für Fehlerklassen wie:
- falsche Serialisierung/Deserialisierung
- Mapping-Fehler (DTO ↔ Domain)
- Schema-/Migration-Probleme
- Auth/Headers/Routing
- Transaktionen, Constraints, Locks
- Timeout-/Retry-Verhalten
Domänenlogik gehört weiterhin in Unit Tests.
3.2 Stabilität vor Realismus
Ein Integration Test soll realitätsnah sein – aber kontrollierbar.
Zu viel Realismus führt zu:
- flakey Tests
- lange Laufzeiten
- schweres Debugging
3.3 Deterministische Umgebung
Integration Tests benötigen:
- isolierte Testdaten
- reproduzierbare Umgebung (Container/Test-Doubles)
- klare Setup- und Cleanup-Routinen
Wenn Tests sich gegenseitig beeinflussen, sind sie falsch geschnitten.
4. Was muss man im Integration Test mocken?
Das ist die Kernfrage.
Integration Tests sollen eine reale Integration prüfen – und alles andere kontrollieren.
Regel:
Mocke alles außerhalb der Systemgrenze, die du gerade testen willst.
Du definierst zuerst den Scope:
- “Ich teste API ↔ Service ↔ DB”
- “Ich teste Service ↔ Message Broker”
- “Ich teste Service ↔ externes Payment Gateway (Stub)”
Dann gilt:
4.1 Was du NICHT mockst (typisch)
✅ Die Integration, die du validieren willst.
Beispiele:
- echte Datenbank (z. B. Testcontainer)
- echter HTTP-Stack bis zum Controller
- echter Serializer/Validator
- echter Message Broker (oder Embedded Broker)
Wenn du hier mockst, verlierst du den Sinn des Tests.
4.2 Was du mockst (typisch)
✅ Alles, was:
- nicht Teil der Aussage des Tests ist
- extern instabil oder teuer ist
- nicht deterministisch ist
- nicht reproduzierbar ist
Typische Kandidaten:
- Drittanbieter-APIs (Payment, SMS, Maps, Mail)
- Echte OAuth/OpenID Provider (z. B. Keycloak) → oft Stub/Fake Token
- Externe Filesysteme/Cloud Storage
- Zeit (Clock), Zufall (Random), GUIDs
- Asynchrone Scheduler/Background Jobs
- Nicht-deterministische Services (z. B. ML/AI APIs)
4.3 Mock vs Fake vs Stub (pragmatisch)
- Stub: liefert feste Antworten (z. B. Payment “OK”)
- Fake: vereinfachte Implementierung (z. B. InMemory-Mailbox)
- Mock: verifiziert Interaktion (“wurde X aufgerufen?”)
Für Integration Tests gilt:
Bevorzuge Stubs/Fakes. Vermeide Interaktions-Mocks.
Interaktions-Mocks koppeln dich an Implementierungsdetails und machen Tests fragil.
5. Typische Integrations-Test-Schnitte (Beispiele)
5.1 API Integration Test
Scope: HTTP → Controller → Service → DB
Mocken: externe APIs, E-Mail, Payment, Clock
Echt: HTTP Stack, Validation, DB
5.2 Persistence Integration Test
Scope: Repository/DAO → DB
Mocken: alles außer DB
Echt: DB, Migrationen, Constraints, Mapping
5.3 Messaging Integration Test
Scope: Producer/Consumer ↔ Broker
Mocken: Downstream Services, externe APIs
Echt: Broker, Serializer, Retry/Deadletter
6. Anti-Patterns
- “Integration Test” mit 20 Mocks → ist oft nur ein schlechter Unit Test
- “Unit Test” mit echter DB → ist ein Integration Test
- E2E-Tests als Ersatz, weil “Mocking zu schwer ist”
- Unkontrollierte Shared Testdaten → flakey Tests
- Tests ohne klare Aussage (“läuft einfach mal durch”)
7. Integration Tests in der Qualitätsstufen-Logik
- Stufe 1: optional, maximal Smoke auf kritischen Integrationspunkt
- Stufe 2: Smoke-Tests für Hauptschnittstellen (DB/API)
- Stufe 3: breite Integration für kritische Schnittstellen (inkl. Failure Modes)
- Stufe 4/5: Traceability + evidenzbasierte Nachweise zu Anforderungen
Kernaussage
Integration Tests sind schwer, weil sie eine bewusste Systemgrenze verlangen.
Du musst zuerst entscheiden:
Welche Integration will ich beweisen?
Dann gilt:
- Diese Integration: echt
- Alles andere: kontrolliert (Stub/Fake/Mock)
Mocking ist kein Selbstzweck.
Es ist ein Werkzeug, um den Test deterministisch und aussagekräftig zu machen.