- 1 Section
- 10 Lessons
- unbegrenzt
- CI/CD, Automatisierung & IaC10
- 1.1Was ist CI/CD?
- 1.2CI/CD-Pipeline aufbauen: Phasen und Stages
- 1.3GitHub Actions: Workflows und YAML
- 1.4GitLab CI/CD: Pipelines und Jobs
- 1.5Jenkins: Grundlagen und Jenkinsfile
- 1.6Automatisiertes Testen in der Pipeline
- 1.7Ansible: Playbooks und Inventory
- 1.8Terraform: Infrastructure as Code
- 1.9Monitoring der Pipeline
- 1.10Aufgaben CI/CD
Automatisiertes Testen in der Pipeline
Eine CI/CD-Pipeline ohne automatisierte Tests ist wie ein Auto ohne Bremsen: solange alles glatt läuft, geht's gut. Aber sobald ein Bug schneller deployed wird als ein Mensch reagieren kann, hast du Production-Probleme. Tests sind die Sicherheitslinie die verhindert, dass kaputter Code in Produktion landet.
Diese Lektion zeigt die wichtigsten Testtypen (Unit, Integration, E2E), das Test-Pyramide-Modell, Code-Coverage, sowie wie du Tests in GitHub Actions, GitLab CI und Jenkins integrierst. Pflicht-Wissen für jeden FIAE.
1) Die Test-Pyramide
Mike Cohn hat das Konzept der Test-Pyramide populär gemacht: ein Modell, das aussagt wie viele Tests welcher Sorte du brauchst. Die Idee: viele schnelle, isolierte Unit-Tests unten, weniger Integration-Tests in der Mitte, ganz wenige End-to-End-Tests oben:
~5%
~15-20%
~75-80%
2) Unit-Tests: das Fundament
Unit-Tests prüfen einzelne Funktionen oder Methoden isoliert von der Außenwelt. Klassische Eigenschaften: schnell, deterministisch, unabhängig. Beispiel in Python mit pytest:
Drei Tests: Standardfall (2+3=5), Edge-Case (negative Zahlen), Fehlerfall (Division durch Null muss Exception werfen). Das ist guter Test-Stil: jeder Test prüft eine konkrete Sache. Name ist sprechend – man weiß ohne Reinzuschauen was getestet wird.
3) Das AAA-Muster: Arrange, Act, Assert
Ein bewährtes Muster für lesbare Tests: jeder Test hat drei Phasen, deutlich getrennt:
Wenn jeder Test diesem Muster folgt, sind sie leicht zu lesen und zu warten. Schau dir den Test an und du weißt sofort: was wird gesetzt, was wird gemacht, was wird geprüft.
4) Test-Frameworks pro Sprache
Die wichtigsten Test-Frameworks – meistens reichen schon die eingebauten Standards:
@Test, AssertJ für lesbare Asserts.5) Code-Coverage: wie viel ist getestet?
Code-Coverage misst welcher Prozentsatz deines Codes durch Tests ausgeführt wird. Tools wie jacoco (Java), coverage.py (Python), istanbul (JS) generieren entsprechende Reports.
assert erhöht Coverage, prüft aber nichts. Realistisches Ziel: 70-80% Line-Coverage, mit Fokus auf kritische Pfade. PaymentGateway mit 45% wäre ein Warnsignal.6) JUnit-XML: das universelle Report-Format
Praktisch alle Test-Frameworks können Reports im JUnit-XML-Format ausgeben. Diese Reports werden von CI-Tools wie GitHub Actions, GitLab CI und Jenkins direkt verarbeitet und im UI angezeigt:
actions/upload-artifact, GitLab artifacts: reports: junit:, Jenkins junit 'target/surefire-reports/*.xml'. Das Tool zeigt dann Statistiken, Trend-Charts, schlägt Alarm bei neuen Failures.7) Tests in der GitHub Actions-Pipeline
Hier ein konkretes Beispiel, wie Tests in eine GitHub Actions-Pipeline integriert werden:
Der Workflow läuft Tests mit Coverage, sendet Coverage an Codecov.io (kostenlos für Open Source), und zeigt Test-Ergebnisse direkt im Pull Request mit grünen/roten Checks.
8) Test-Strategien für Integration-Tests
Integration-Tests brauchen oft echte Dependencies wie Datenbanken oder externe APIs. Es gibt mehrere Strategien wie man damit in CI/CD umgeht:
| Strategie | Wie | Wann |
|---|---|---|
| Mock | Fake-Implementierungen statt echter Services | Wenn der Service eh nicht im Fokus steht |
| In-Memory | SQLite statt PostgreSQL, In-Memory-Caches | Für schnelle DB-Tests |
| TestContainers | Docker-Container für echte Services (Postgres, Redis, Kafka) | Für realistische Integration-Tests |
| Stubs | Vorgefertigte Antworten für HTTP-Mocks (WireMock) | Für externe APIs |
| Service Virtualization | Komplettes Faken externer Systeme | Enterprise mit vielen Abhängigkeiten |
TestContainers ist heute die populärste Lösung für realistische Integration-Tests – Java-Bibliothek (mittlerweile auch für andere Sprachen), die Docker-Container für Tests startet:
Vor dem Test startet automatisch ein Postgres-Container. Tests laufen gegen echte Datenbank. Nach den Tests wird der Container gestoppt. Realistisch wie Production, ohne externe Abhängigkeiten.
9) Das Problem: flaky Tests
Ein häufiges Problem in CI/CD: flaky Tests. Das sind Tests, die manchmal grün und manchmal rot sind, ohne dass sich der Code ändert. Sie sind ein riesiges Übel – Entwickler fangen an die Test-Ergebnisse zu ignorieren („Achso, dieser Test ist eh flaky, einfach nochmal laufen lassen").
- Zeitabhängigkeiten:
Thread.sleep(100)– mal reicht's, mal nicht - Race Conditions: zwei Threads die sich gegenseitig stören
- Externe Services: Netzwerk-Timeouts, langsame APIs
- Reihenfolge-Abhängigkeit: Test A funktioniert nur wenn Test B vorher lief
- Geteilter Zustand: Static-Variables, gemeinsame DB-Tables
- Datums-Bugs: Test funktioniert bis zur Zeitumstellung oder am Wochenende
- UI-Tests: Element noch nicht gerendert, Animation noch nicht fertig
10) Quality Gates und Test-Strategien
In professionellen Pipelines sind Tests verbunden mit Quality Gates – Schwellenwerten die erfüllt sein müssen:
- Test-Pass: alle Tests grün, sonst Pipeline-Abbruch (Standard)
- Coverage-Threshold: mindestens 80% Coverage – sonst Fail
- Coverage darf nicht sinken: Diff-Coverage prüft neuer Code >= 90%
- Maximale Test-Dauer: einzelne Tests über 5 Sekunden → Warnung
- Keine Skipped Tests: bei Production-Branch erlaubst du keine
@Ignore - Mutation Testing: PIT/Stryker simulieren Bugs, prüfen ob Tests sie finden
Bei GitLab sind Quality Gates über SonarQube-Integration üblich. Bei GitHub Actions über Branch Protection Rules: man kann definieren, dass bestimmte Checks grün sein müssen bevor man mergen darf.
11) Test-Pipeline-Optimierung
Wenn deine Tests die Pipeline ausbremsen, hier die wichtigsten Optimierungen:
- Parallelisieren: Tests auf mehrere CPU-Kerne (
pytest -n auto) oder Runner verteilen - Test-Splitting: Test-Suite auf mehrere Jobs aufteilen die parallel laufen
- Test-Selection: nur Tests laufen lassen die zu geänderten Files passen
- Fail Fast: bei erstem Fehlschlag abbrechen, statt alle Tests durchlaufen zu lassen
- Caching: Test-Datenbank-Snapshots, Build-Artefakte zwischen Runs cachen
- Smoke-Tests zuerst: schnelle „läuft überhaupt was?"-Tests vor den langen
- Slow Tests aussondern: separater Job für Tests > 30s, läuft nur nightly
Faustregel: Tests sollten unter 10 Minuten dauern. Wenn länger, splitte sie auf oder optimiere. Eine 30-Minuten-Test-Pipeline frustriert Entwickler und sie umgehen sie irgendwann.
Zusammenfassung
Automatisierte Tests sind das Sicherheitsnetz jeder CI/CD-Pipeline. Test-Pyramide: viele schnelle Unit-Tests (75-80%), einige Integration-Tests (15-20%), wenige langsame E2E-Tests (5%). AAA-Pattern: Arrange-Act-Assert für lesbare Tests. Frameworks: JUnit (Java), pytest (Python), Jest/Vitest (JS), Playwright/Cypress (E2E). Coverage messen mit jacoco/coverage.py/istanbul – Ziel 70-80%, kein Selbstzweck. JUnit-XML ist das universelle Report-Format das alle CI-Tools verstehen. TestContainers für realistische Integration-Tests mit echten DBs in Docker. Flaky Tests aggressiv jagen und fixen – sonst verliert das Team Vertrauen. Quality Gates mit Coverage-Thresholds, Test-Pass-Rate, max. Test-Dauer. Optimierung: Parallelisierung, Test-Splitting, Caching. Pflichtwissen für jeden Entwickler.
