Regressionstests
Regressionstests stellen sicher, dass neue Änderungen, Bugfixes oder Refactorings keine bestehenden Funktionen zerstören. Sie sind ein unverzichtbarer Bestandteil jeder Qualitätssicherung, besonders in agilen Teams mit kurzen Release-Zyklen. Ohne Regressionstests wächst die Angst vor Änderungen, und der Code veraltert.
In a Nutshell
- Regressionstests prüfen, dass alte Funktionen weiterhin funktionieren.
- Sie werden nach jeder relevanten Änderung ausgeführt.
- Automatisierung ist essenziell, um Regressionstests skalierbar zu halten.
- Unit, Integration und E2E Tests können alle als Regressionstests dienen.
- Eine gute Regressionstest-Strategie priorisiert kritische Pfade.
Kompakte Fachbeschreibung
Regressionstests sind Tests, die bereits funktionierende Features wiederholt prüfen, nachdem sich an der Software etwas geändert hat. Ziel ist es, sogenannte Regressionsfehler zu entdecken, also Fehler, die durch neue Änderungen in zuvor korrekten Bereichen entstehen. Sie können manuell oder automatisiert durchgeführt werden, wobei Automatisierung bei häufigen Änderungen deutlich effizienter ist.
Regressionstests sind keine eigene Testart im engeren Sinne, sondern eine Teststrategie: Sie entscheiden, welche bereits vorhandenen Tests nach einer Änderung erneut ausgeführt werden müssen. Die Auswahl kann vollumfaenglich, risikobasiert oder durch Impact-Analyse gesteuert sein.
Wann werden Regressionstests ausgeführt?
Regressionstests werden immer dann eingesetzt, wenn sich der Code oder die Umgebung der Software ändert. Die wichtigsten Ausloeser sind:
- Nach Code-Aenderungen oder Bugfixes: Jede Aenderung kann Nebenwirkungen haben. Regressionstests stellen sicher, dass bisherige Funktionen nicht versehentlich kaputtgehen.
- Nach Refactorings: Beim Umstrukturieren von Code soll das Verhalten gleich bleiben. Regressionstests geben Sicherheit, dass keine Verhaltensänderung eingetreten ist.
- Nach Updates von Abhaengigkeiten: Neue Versionen von Bibliotheken oder Frameworks können inkompatible Aenderungen enthalten. Regressionstests pruefen, ob das System weiterhin korrekt funktioniert.
- Nach Merge in den Hauptzweig: Bevor Code in den main branch integriert wird, laufen Regressionstests, um Konflikte und Seiteneffekte frueh zu erkennen.
- Vor einem Release: Kurz vor der Auslieferung wird eine vollstaendige Regressionssuite ausgefuehrt, um die Gesamtqualitaet zu bestaetigen.
- Bei regelmäßigen Nightly Builds: Automatisierte Nachtlaufe erfassen Regressionen, die waehrend des Tages nicht bemerkt wurden.
Arten von Regressionstests
Unit-Regressionstests
Unit-Regressionstests pruefen einzelne Funktionen oder Klassen nach Aenderungen. Sie sind schnell und laufen oft, idealerweise bei jedem Commit. Sie sind die erste Verteidigungslinie gegen Regressionen, weil sie isoliert und in Millisekunden ausfuehren. Ein typisches Beispiel: Eine Funktion zur Rabattberechnung wird geaendert. Die Unit-Tests pruefen alle bisherigen Rabattregeln und stellen sicher, dass die Ergebnisse unveraendert sind.
Integration-Regressionstests
Integration-Regressionstests pruefen Schnittstellen und Zusammenspiele zwischen Modulen, die von einer Aenderung betroffen sein koennten. Sie sind langsamer als Unit-Tests, aber wichtig, um Seiteneffekte an Modulgrenzen zu finden. Ein Beispiel: Nach einer Aenderung an der Preisberechnung wird getestet, ob Warenkorb, Zahlungsanbindung und Rechnungserstellung weiterhin korrekt zusammenarbeiten.
E2E-Regressionstests
E2E-Regressionstests validieren kritische Endnutzer-Ablaeufe, beispielsweise den Bestellprozess in einem Shop. Sie sind die langsamsten und aufwendigsten Tests, decken aber die gesamte Kette ab. Sie sollten gezielt fuer kritische Geschaeftsprozesse eingesetzt werden, nicht fuer jede Kleinigkeit.
Strategien fuer Regressionstests
Vollstaendige Regression
Alle vorhandenen Tests werden ausgefuehrt. Das ist die sicherste Variante, aber bei grossen Test-Suiten sehr zeitaufwendig. Sie wird typischerweise nur vor Releases oder in Nightly Builds eingesetzt.
Risikobasierte Regression
Es werden nur die Tests ausgefuehrt, die kritische oder haeufig genutzte Funktionen abdecken. Diese Strategie erfordert eine Priorisierung der Tests nach Kritikalitaet und Nutzungshaeufigkeit.
Test-Impact-Analyse
Die Test-Impact-Analyse identifiziert, welche Code-Bereiche von einer Aenderung betroffen sind, und fuehrt nur die Tests aus, die diese Bereiche abdecken. Dies erfordert Werkzeuge, die Abhaengigkeiten im Code analysieren koennen.
Praxisbeispiel
Das folgende Beispiel zeigt, wie Regressionstests in der Praxis eingesetzt werden. Es wurde gewaehlt, weil es alle drei Testebenen verbindet und zeigt, wie eine gezielte Aenderung zu einer systematischen Teststrategie fuehrt.
Ein Entwickler ändert die Rabattlogik im Checkout.
Regressionstests:
- Unit Tests für alle Rabattregeln
- Integrationstests für Warenkorb und Preisberechnung
- E2E Test für den kompletten Checkout-Flow
- Exploratives Testen der alten Rabattfunktionen
Warum diese Tests?
- Unit Tests: Die Rabattlogik ist eine isolierbare Funktion. Unit Tests pruefen jede Rabattregel einzeln und stellen sicher, dass die Berechnung fuer alle bisherigen Faelle korrekt bleibt.
- Integrationstests: Der Warenkorb und die Preisberechnung sind direkt von der Rabattlogik abhaengig. Integrationstests pruefen, ob die Gesamtpreisberechnung mit den neuen Rabattregeln weiterhin korrekt ist.
- E2E Test: Der komplette Checkout-Flow ist der kritischste Geschaeftsprozess. Ein E2E Test stellt sicher, dass der Nutzer den Kauf abschliessen kann, ohne dass es zu Fehlern kommt.
- Exploratives Testen: Automatisierte Tests decken bekannte Faelle ab. Exploratives Testen findet unerwartete Seiteneffekte, die die Tests nicht abdecken.
Vorteile und Nachteile
| Vorteile | Nachteile |
|---|---|
| Schutz vor Regressionsfehlern | Wachsender Testumfang bei vielen Features |
| Vertrauen in Refactorings und Code-Aenderungen | Lange Laufzeiten ohne gute Strategie |
| Sicherere und haeufigere Releases | Wartungsaufwand fuer Tests |
| Fruehes Erkennen von Seiteneffekten | Manuelle Regressionstests sind teuer und langsam |
| Lebende Dokumentation des erwarteten Verhaltens | False Positives koennen Vertrauen zerstoeren |
| Objektive Qualitaetsbewertung vor Release | Initialer Aufwand fuer Automatisierung |
Best Practices
- Automatisieren: Manuelle Regressionstests sind bei haeufigen Aenderungen nicht skalierbar.
- Priorisieren: Nicht alle Tests sind gleich wichtig. Kritische Pfade zuerst.
- Wartbar halten: Tests muessen bei Code-Aenderungen leicht anpassbar sein.
- Schnell halten: Lange Test-Suiten bremsen die Entwicklung. Parallelisierung und gezielte Auswahl helfen.
- In CI/CD integrieren: Regressionstests sollten automatisch bei jedem Commit oder Merge laufen.
- False Positives vermeiden: Instabile Tests zerstoeren das Vertrauen in die Suite.
- Test-Impact-Analyse nutzen: Nur betroffene Tests ausfuehren, um Zeit zu sparen.
Ausführliches Praxisbeispiel: FastAPI + NiceGui Projekt mit Docker und CI/CD
Projektkontext
Ein Projekt besteht aus:
- FastAPI als Backend — stellt API-Endpunkte für Text-Konvertierungstools bereit (z.B. Markdown→HTML, JSON→YAML, Base64-De-/Encoding, Text-Statistiken)
- NiceGui als Frontend — webbasierte UI, die die API-Endpunkte aufruft und Ergebnisse anzeigt
- Docker — das Tool läuft lokal zur Entwicklung und auf dem Server via Docker-Container
- Zusätzliche Module — z.B.
pydanticfür Validierung,httpxfür asynchrone HTTP-Requests,python-slugifyfür URL-Slug-Erzeugung
Das Problem beim Vibecoding: KI-gestützte Code-Generierung ändert oft unbeabsichtigt andere Dateien, entfernt Bibliotheken oder verändert Importe. Eine Funktion, die gestern funktionierte, ist plötzlich kaputt — ohne dass der Entwickler es bemerkt, weil die Änderung an einer ganz anderen Stelle gemacht wurde.
Projektstruktur
my-text-tools/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI-App, registriert Router
│ ├── routers/
│ │ ├── __init__.py
│ │ ├── markdown.py # /api/markdown → HTML
│ │ ├── json_yaml.py # /api/json-to-yaml, /api/yaml-to-json
│ │ ├── base64.py # /api/base64/encode, /api/base64/decode
│ │ └── stats.py # /api/stats (Wörter, Zeichen, Zeilen)
│ ├── models/
│ │ ├── __init__.py
│ │ └── schemas.py # Pydantic-Modelle für Request/Response
│ ├── services/
│ │ ├── __init__.py
│ │ ├── converter.py # Kernlogik: Konvertierungsfunktionen
│ │ └── slugify.py # Slug-Erzeugung
│ └── ui/
│ ├── __init__.py
│ └── nicegui_app.py # NiceGui-Frontend, ruft API auf
├── tests/
│ ├── __init__.py
│ ├── conftest.py # pytest-Fixtures (Test-Client, Mocks)
│ ├── unit/
│ │ ├── test_converter.py
│ │ ├── test_slugify.py
│ │ └── test_models.py
│ ├── integration/
│ │ ├── test_markdown_api.py
│ │ ├── test_json_yaml_api.py
│ │ ├── test_base64_api.py
│ │ └── test_stats_api.py
│ └── e2e/
│ └── test_ui_flows.py # NiceGui-UI-Tests via Playwright
├── Dockerfile
├── docker-compose.yml
├── docker-compose.test.yml # Test-Environment mit isolierter DB
├── requirements.txt
├── requirements-dev.txt # pytest, pytest-asyncio, httpx, playwright
├── .github/
│ └── workflows/
│ ├── ci.yml # Lint + Unit + Integration bei jedem Push
│ └── nightly.yml # Vollständige Regressionssuite nachts
├── Makefile # make test, make test-unit, make test-e2e
└── pytest.ini
Schritt 1: Unit-Regressionstests mit pytest
Unit-Tests prüfen die Kernlogik isoliert — ohne Datenbank, ohne Netzwerk, ohne UI.
# tests/unit/test_converter.py
import pytest
from app.services.converter import (
markdown_to_html,
json_to_yaml,
yaml_to_json,
base64_encode,
base64_decode,
text_statistics,
)
class TestMarkdownToHtml:
"""Regressionstests für Markdown-Konvertierung."""
def test_simple_heading(self):
assert markdown_to_html("# Titel") == "<h1>Titel</h1>"
def test_bold_text(self):
assert markdown_to_html("**fett**") == "<strong>fett</strong>"
def test_code_block(self):
md = "```python\nprint('hello')\n```"
result = markdown_to_html(md)
assert "<code>" in result
assert "print('hello')" in result
def test_empty_input(self):
assert markdown_to_html("") == ""
def test_nested_lists(self):
md = "- Item 1\n - Subitem 1.1"
result = markdown_to_html(md)
assert "<ul>" in result
assert "<li>Item 1" in result
# Regression: Vibecoding entfernt Bibliothek → ImportError
def test_module_imports_successfully(self):
"""Stellt sicher, dass der Converter importierbar bleibt.
Wenn Vibecoding z.B. 'markdown' aus requirements.txt entfernt,
schlägt dieser Test fehl."""
from app.services import converter
assert hasattr(converter, 'markdown_to_html')
class TestJsonYamlConversion:
"""Regressionstests für JSON↔YAML-Konvertierung."""
def test_json_to_yaml_basic(self):
json_input = '{"name": "test", "value": 42}'
result = json_to_yaml(json_input)
assert "name: test" in result
assert "value: 42" in result
def test_roundtrip_json_yaml_json(self):
"""JSON → YAML → JSON muss identisch sein."""
import json
original = {"name": "test", "list": [1, 2, 3]}
json_str = json.dumps(original)
yaml_str = json_to_yaml(json_str)
back = yaml_to_json(yaml_str)
assert json.loads(back) == original
def test_nested_structures(self):
json_input = '{"outer": {"inner": {"deep": true}}}'
result = json_to_yaml(json_input)
assert "inner:" in result
assert "deep: true" in result
class TestBase64:
"""Regressionstests für Base64-De-/Encoding."""
def test_encode_decode_roundtrip(self):
original = "Hello, World!"
encoded = base64_encode(original)
decoded = base64_decode(encoded)
assert decoded == original
def test_encode_empty_string(self):
assert base64_encode("") == ""
def test_decode_invalid_input_raises(self):
with pytest.raises(Exception):
base64_decode("!!!invalid_base64!!!")
class TestTextStatistics:
"""Regressionstests für Text-Statistiken."""
def test_word_count(self):
stats = text_statistics("hello world foo")
assert stats["words"] == 3
def test_empty_text(self):
stats = text_statistics("")
assert stats["words"] == 0
assert stats["characters"] == 0
assert stats["lines"] == 0
def test_multiline(self):
stats = text_statistics("line1\nline2\nline3")
assert stats["lines"] == 3
# tests/unit/test_slugify.py
from app.services.slugify import slugify
class TestSlugify:
"""Regression: Wenn python-slugify aus requirements entfernt wird,
schlägt dieser Test fehl — schützt vor unbemerktem Bibliotheksverlust."""
def test_basic_slug(self):
assert slugify("Hello World") == "hello-world"
def test_german_umlauts(self):
assert slugify("Übergröße") == "ubergrose"
def test_special_characters(self):
assert slugify("Python 3.12!@#") == "python-312"
def test_empty_string(self):
assert slugify("") == ""
Schritt 2: Integration-Regressionstests mit pytest + httpx
Integrationstests prüfen die API-Endpunkte über FastAPI’s TestClient.
# tests/conftest.py
import pytest
from fastapi.testclient import TestClient
from app.main import app
@pytest.fixture
def client():
"""FastAPI Test-Client für Integrationstests."""
return TestClient(app)
@pytest.fixture
def sample_markdown():
return "# Test\n\n**Bold** text with `code`."
# tests/integration/test_markdown_api.py
class TestMarkdownAPI:
"""Regressionstests für den /api/markdown Endpunkt."""
def test_markdown_to_html_success(self, client, sample_markdown):
response = client.post("/api/markdown", json={"text": sample_markdown})
assert response.status_code == 200
data = response.json()
assert "<h1>Test</h1>" in data["html"]
assert "<strong>Bold</strong>" in data["html"]
def test_markdown_empty_input(self, client):
response = client.post("/api/markdown", json={"text": ""})
assert response.status_code == 200
assert response.json()["html"] == ""
def test_markdown_missing_field(self, client):
"""Regression: Pydantic-Validierung muss aktiv bleiben.
Wenn Vibecoding das Modell ändert, schlägt dieser Test fehl."""
response = client.post("/api/markdown", json={})
assert response.status_code == 422 # Validation Error
def test_markdown_invalid_json(self, client):
response = client.post("/api/markdown", data="not json")
assert response.status_code == 422
# tests/integration/test_stats_api.py
class TestStatsAPI:
"""Regressionstests für /api/stats."""
def test_stats_basic(self, client):
response = client.post("/api/stats", json={"text": "hello world"})
assert response.status_code == 200
data = response.json()
assert data["words"] == 2
assert data["characters"] == 11
def test_stats_empty(self, client):
response = client.post("/api/stats", json={"text": ""})
assert response.status_code == 200
assert response.json()["words"] == 0
# Regression: Stellt sicher, dass der Endpunkt überhaupt existiert.
# Wenn Vibecoding einen Router entfernt, schlägt dies fehl.
def test_stats_endpoint_exists(self, client):
response = client.post("/api/stats", json={"text": "test"})
assert response.status_code != 404
Schritt 3: E2E-Regressionstests mit Playwright
E2E-Tests prüfen die NiceGui-Oberfläche über einen echten Browser.
# tests/e2e/test_ui_flows.py
"""E2E-Regressionstests für die NiceGui-Oberfläche.
Setzt voraus, dass die App läuft (docker-compose up -d)."""
import pytest
from playwright.sync_api import Page, expect
BASE_URL = "http://localhost:8080"
class TestMarkdownConverterUI:
"""Prüft, ob die Markdown-Konvertierung über die UI funktioniert."""
def test_markdown_input_and_output(self, page: Page):
page.goto(BASE_URL)
page.fill("[data-testid='markdown-input']", "# Hallo Welt")
page.click("[data-testid='convert-button']")
output = page.locator("[data-testid='markdown-output']")
expect(output).to_contain_text("Hallo Welt")
expect(output).to_contain_text("<h1>")
def test_clear_button(self, page: Page):
page.goto(BASE_URL)
page.fill("[data-testid='markdown-input']", "# Test")
page.click("[data-testid='clear-button']")
assert page.locator("[data-testid='markdown-input']").input_value() == ""
class TestNavigationRegression:
"""Stellt sicher, dass alle UI-Tabs erreichbar bleiben.
Wenn Vibecoding einen Tab entfernt, schlägt dies fehl."""
@pytest.mark.parametrize("tab_name", [
"Markdown", "JSON/YAML", "Base64", "Statistiken"
])
def test_tab_accessible(self, page: Page, tab_name):
page.goto(BASE_URL)
page.click(f"text={tab_name}")
# Prüft, dass der Tab-Inhalt sichtbar ist
content = page.locator("[data-testid='tab-content']")
expect(content).to_be_visible()
Schritt 4: Docker-Test-Setup
# Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# NiceGui + FastAPI starten
EXPOSE 8080
CMD ["python", "-m", "app.main"]
# docker-compose.test.yml
# Isoliertes Test-Environment — kein Zugriff auf produktive Daten
version: "3.9"
services:
app-test:
build:
context: .
dockerfile: Dockerfile
ports:
- "8081:8080" # Anderer Port als Produktion
environment:
- TESTING=true
- LOG_LEVEL=DEBUG
command: >
bash -c "pip install -r requirements-dev.txt &&
pytest tests/unit tests/integration -v --tb=short &&
pytest tests/e2e -v --tb=short"
Schritt 5: CI/CD-Pipeline mit GitHub Actions
# .github/workflows/ci.yml
name: CI Regression Tests
on:
push:
branches: [main, dev]
pull_request:
branches: [main]
jobs:
unit-and-integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install -r requirements.txt -r requirements-dev.txt
- run: pytest tests/unit tests/integration -v --tb=short --junitxml=results.xml
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: results.xml
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install -r requirements.txt -r requirements-dev.txt
- run: playwright install --with-deps chromium
- name: Start app in background
run: |
python -m app.main &
sleep 5
- run: pytest tests/e2e -v --tb=short
docker-build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: docker compose -f docker-compose.test.yml up --exit-code-from app-test
# .github/workflows/nightly.yml
name: Nightly Full Regression
on:
schedule:
- cron: "0 2 * * *" # Jede Nacht um 02:00 Uhr
jobs:
full-regression:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: pip install -r requirements.txt -r requirements-dev.txt
- run: playwright install --with-deps chromium
- name: Start app
run: python -m app.main & sleep 5
- name: Full regression suite
run: pytest -v --tb=long --junitxml=nightly-results.xml
- name: Notify on failure
if: failure()
run: |
echo "::error::Nightly regression failed — check logs"
Schritt 6: Makefile für lokale Ausführung
# Makefile
.PHONY: test test-unit test-integration test-e2e test-docker test-watch
test: test-unit test-integration
@echo "✅ Unit + Integration Tests bestanden"
test-unit:
pytest tests/unit -v --tb=short
test-integration:
pytest tests/integration -v --tb=short
test-e2e:
pytest tests/e2e -v --tb=short
test-docker:
docker compose -f docker-compose.test.yml up --exit-code-from app-test
test-watch:
ptw -- -v --tb=short tests/
test-coverage:
pytest --cov=app --cov-report=html tests/unit tests/integration
@echo "📊 Coverage Report: htmlcov/index.html"
Schritt 7: Dokumentation der Tests
Jede Test-Datei sollte dokumentiert sein. Empfohlene Struktur:
docs/
├── testing.md # Test-Strategie und Anleitung
├── test-cases.md # Liste aller Testfälle mit Beschreibung
└── troubleshooting.md # Bekannte Probleme und Lösungen
docs/testing.md sollte enthalten:
- Test-Strategie — welche Tests wann laufen (Unit bei Commit, Integration bei PR, E2E nightly)
- Ausführung —
make test,make test-unit,make test-docker - CI/CD-Integration — welche Workflows existieren und wann sie triggern
- Neue Tests hinzufügen — Konventionen für Dateinamen, Fixtures, Assertions
- Test-Abdeckung —
make test-coverageund Ziel-Coverage (z.B. ≥ 80 %) - Troubleshooting — häufige Fehlschläge und Lösungen
Schritt 8: Empfehlungen speziell für Vibecoding
Beim Vibecoding (KI-gestützte Code-Generierung) entstehen Regressionen oft durch:
- Entfernte Imports — die KI löscht einen
importin einer Datei, den eine andere Datei benötigt - Geänderte Funktionssignaturen — Parameter werden umbenannt oder entfernt
- Gelöschte Hilfsfunktionen — die KI hält eine Funktion für “unbenutzt” und entfernt sie
- Veränderte Pydantic-Modelle — Felder werden entfernt oder umbenannt, API-Validierung ändert sich
Schutzmaßnahmen:
-
Import-Guard-Tests — jeder Test-File beginnt mit einem Test, der alle relevanten Module importiert:
def test_module_imports(): """Regression: Stellt sicher, dass alle Module importierbar bleiben.""" import app.services.converter import app.services.slugify import app.routers.markdown import app.routers.stats -
API-Vertrags-Tests — testen, dass Endpunkte mit erwarteten Feldern antworten:
def test_stats_response_schema(client): """Regression: Wenn Pydantic-Modell geändert wird, schlägt dies fehl.""" response = client.post("/api/stats", json={"text": "test"}) data = response.json() assert "words" in data assert "characters" in data assert "lines" in data -
Abhängigkeits-Check — ein Test, der
requirements.txtparst und prüft, ob alle importierten Pakete gelistet sind:def test_all_imports_in_requirements(): """Regression: Wenn Vibecoding einen Import entfernt, aber Code noch darauf verweist, oder umgekehrt.""" # Parse requirements.txt with open("requirements.txt") as f: requirements = { line.split("==")[0].split(">=")[0].strip().lower() for line in f if line.strip() and not line.startswith("#") } # Prüfe kritische Pakete assert "fastapi" in requirements assert "nicegui" in requirements assert "pydantic" in requirements assert "httpx" in requirements assert "python-slugify" in requirements -
Pre-Commit-Hook — lässt Unit-Tests vor jedem Commit laufen:
# .git/hooks/pre-commit #!/bin/bash pytest tests/unit -v --tb=short || exit 1 -
Git-Diff-Review — nach jedem Vibecoding-Session
git diffprüfen:git diff --stat # Welche Dateien wurden geändert? git diff requirements.txt # Wurden Pakete entfernt? git diff app/services/ # Wurde Kernlogik verändert?
Zusammenfassung: Test-Pyramide für dieses Projekt
| Ebene | Werkzeug | Wann | Dauer | Anzahl |
|---|---|---|---|---|
| Unit | pytest | Bei jedem Commit | < 5 s | 30–50 |
| Integration | pytest + TestClient | Bei jedem PR | < 30 s | 15–25 |
| E2E | Playwright | Nightly + vor Release | 2–5 min | 5–10 |
| Docker | docker-compose.test | Bei jedem PR | 1–2 min | 1 Suite |
Regel: Wenn ein Vibecoding-Change eine Funktion ändert, müssen mindestens die Unit- und Integrationstests für diesen Bereich grün sein, bevor der Commit erfolgt.
Wichtige Werkzeuge
- JUnit / pytest / Jest: Frameworks fuer Unit-Regressionstests.
- Selenium / Cypress / Playwright: Werkzeuge fuer E2E-Regressionstests.
- Postman / REST Assured: Fuer API-Regressionstests.
- TestNG / NUnit: Frameworks mit erweiterten Test-Management-Funktionen.
- Jenkins / GitHub Actions / GitLab CI: CI/CD-Pipelines fuer automatisierte Regressionstest-Laeufe.
Prüfungsrelevante Stichpunkte
- Regressionstest: Test, der sicherstellt, dass bestehende Funktionen nach Aenderungen weiterhin funktionieren.
- Regressionsfehler: Fehler, der durch eine neue Aenderung in einem zuvor funktionierenden Bereich entsteht.
- Ausloeser: Code-Aenderungen, Bugfixes, Refactorings, Dependency-Updates, Merges, Releases.
- Testebenen: Unit, Integration und E2E als Regressionstests einsetzbar.
- Strategien: Vollstaendige Regression, risikobasierte Regression, Test-Impact-Analyse.
- Automatisierung: Essenziell fuer skalierbare und wiederholbare Regressionstests.
- Smoke Test: Minimaler Test, der prueft, ob das System grundsaetzlich laeuft.
- Sanity Test: Gezielter Test, der eine kleine Aenderung validiert.
- Nightly Build: Naechtlicher automatisierter Testlauf zur Frueherkennung.
- CI/CD-Integration: Regressionstests laufen automatisch bei jedem Commit oder Merge.
- Wartung: Tests muessen bei Code-Aenderungen aktuell gehalten werden.
- False Positives: Instabile Tests koennen das Vertrauen in die Suite zerstoeren.
Wichtigste Quellen
- https://www.guru99.com/regression-testing.html
- https://www.atlassian.com/continuous-delivery/software-testing/regression-testing
- https://en.wikipedia.org/wiki/Regression_testing
Häufig gestellte Fragen
Was ist ein Regressionstest?
Ein Regressionstest prueft, dass bestehende Funktionen nach Aenderungen am Code weiterhin korrekt funktionieren. Er verhindert, dass neue Features oder Bugfixes vorhandene Funktionen kaputt machen.
Wann fuehrt man Regressionstests durch?
Nach Code-Aenderungen, Bugfixes, Refactorings, Dependency-Updates, Merges in den Hauptzweig, vor Releases und in Nightly Builds.
Was ist ein Regressionsfehler?
Ein Regressionsfehler ist ein Fehler, der durch eine neue Aenderung in einem zuvor funktionierenden Bereich entsteht. Er ist oft schwer zu finden, weil die Aenderung an einer anderen Stelle gemacht wurde.
Warum automatisiert man Regressionstests?
Weil sie schnell, wiederholbar und skalierbar sind. Manuelle Regressionstests sind bei haeufigen Aenderungen zu langsam und fehleranfaellig.
Auf welchen Ebenen laufen Regressionstests?
Auf allen Ebenen: Unit-Tests pruefen isolierte Funktionen, Integrationstests pruefen Schnittstellen und E2E-Tests validieren komplette Nutzeraeblaeufe.
Was ist eine Regressionstest-Strategie?
Eine Strategie, die festlegt, welche Tests nach einer Aenderung ausgefuehrt werden. Moegliche Ansaetze sind vollstaendige Regression, risikobasierte Auswahl oder Test-Impact-Analyse.
Sollte man alle Tests immer wiederholen?
Nein. Bei grossen Test-Suiten ist das zu zeitaufwendig. Stattdessen sollte man risikobasiert priorisieren oder eine Test-Impact-Analyse durchfuehren.
Was ist ein Smoke Test?
Ein Smoke Test ist ein minimaler Test, der prueft, ob das System grundsaetzlich laeuft und die wichtigsten Funktionen verfuegbar sind.
Was ist ein Sanity Test?
Ein Sanity Test ist ein sehr gezielter Test, der eine kleine Aenderung validiert. Er ist schneller als eine vollstaendige Regressionssuite.
Wie waehlt man Regressionstests aus?
Nach Kritikalitaet der Funktion, Haeufigkeit der Nutzung und den Auswirkungen der Aenderung. Kritische Pfade werden immer getestet, weniger wichtige nur bei Bedarf.
Was ist ein Vorteil von Regressionstests?
Sie geben Vertrauen in Aenderungen und Refactorings, ermoeglichen haeufigere Releases und reduzieren das Risiko von Seiteneffekten in Produktion.
Was ist ein Nachteil manueller Regressionstests?
Sie sind teuer, langsam und fehleranfaellig. Bei haeufigen Aenderungen sind sie nicht skalierbar und fuehren oft zu unvollstaendiger Abdeckung.
Wie oft sollten Regressionstests laufen?
Automatisierte Regressionstests sollten bei jedem Commit oder Merge laufen. Zusaetzlich koennen Nightly Builds eine vollstaendige Regressionssuite ausfuehren.
Was ist eine Test-Impact-Analyse?
Die Test-Impact-Analyse identifiziert, welche Code-Bereiche von einer Aenderung betroffen sind, und fuehrt nur die Tests aus, die diese Bereiche abdecken.
Koennen Regressionstests verhindern, dass Bugs entstehen?
Sie verhindern keine Bugs direkt, finden aber schnell Folgefehler, die durch Aenderungen entstanden sind, bevor diese in Produktion gelangen.
Was ist ein False Positive bei Regressionstests?
Ein False Positive ist ein Test, der fehlschlaegt, obwohl der Code korrekt ist. Haeufige Ursachen sind instabile Tests, Timing-Probleme oder fehlerhafte Testdaten.
Was ist der Unterschied zwischen Smoke Test und Sanity Test?
Ein Smoke Test prueft das System breit, aber flach. Ein Sanity Test prueft gezielt eine bestimmte Aenderung. Smoke Tests sind breiter, Sanity Tests tiefer.
Welche Werkzeuge eignen sich fuer Regressionstests?
JUnit, pytest und Jest fuer Unit-Tests. Selenium, Cypress und Playwright fuer E2E-Tests. Postman fuer API-Tests. Jenkins und GitHub Actions fuer CI/CD-Integration.
Was ist ein Nightly Build?
Ein Nightly Build ist ein automatisierter Build- und Testlauf, der jede Nacht ausgefuehrt wird, um Regressionen zu erkennen, die waehrend des Tages nicht bemerkt wurden.
Was ist der Unterschied zwischen Regressionstest und Retest?
Ein Retest prueft, ob ein spezifischer Bug nach dem Fix behoben ist. Ein Regressionstest prueft, ob andere Funktionen durch den Fix nicht kaputtgegangen sind.
Weiter im Software Testing Lernpfad
Der nächste Artikel im Software Testing Lernpfad behandelt Akzeptanztests — wie Akzeptanztests sicherstellen, dass die Anforderungen erfüllt sind.



