Skip to content
IRC-CodingIRC-Coding
RegressionstestsRegression TestingTestautomatisierungSoftwarequalitätUnit TestsIntegration TestsE2E Tests

Regressionstests: Sicherstellen, dass Änderungen nichts zerstören

Lerne Regressionstests kennen: Ziele, Strategien, Automatisierung, Werkzeuge und Best Practices. So schützt Du bestehende Funktionen vor Fehlern durch neue Änderungen.

S

schutzgeist

15 min read
Regressionstests: Sicherstellen, dass Änderungen nichts zerstören

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

VorteileNachteile
Schutz vor RegressionsfehlernWachsender Testumfang bei vielen Features
Vertrauen in Refactorings und Code-AenderungenLange Laufzeiten ohne gute Strategie
Sicherere und haeufigere ReleasesWartungsaufwand fuer Tests
Fruehes Erkennen von SeiteneffektenManuelle Regressionstests sind teuer und langsam
Lebende Dokumentation des erwarteten VerhaltensFalse Positives koennen Vertrauen zerstoeren
Objektive Qualitaetsbewertung vor ReleaseInitialer 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. pydantic für Validierung, httpx für asynchrone HTTP-Requests, python-slugify fü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:

  1. Test-Strategie — welche Tests wann laufen (Unit bei Commit, Integration bei PR, E2E nightly)
  2. Ausführungmake test, make test-unit, make test-docker
  3. CI/CD-Integration — welche Workflows existieren und wann sie triggern
  4. Neue Tests hinzufügen — Konventionen für Dateinamen, Fixtures, Assertions
  5. Test-Abdeckungmake test-coverage und Ziel-Coverage (z.B. ≥ 80 %)
  6. 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 import in 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:

  1. 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
  2. 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
  3. Abhängigkeits-Check — ein Test, der requirements.txt parst 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
  4. 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
  5. Git-Diff-Review — nach jedem Vibecoding-Session git diff prü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

EbeneWerkzeugWannDauerAnzahl
UnitpytestBei jedem Commit< 5 s30–50
Integrationpytest + TestClientBei jedem PR< 30 s15–25
E2EPlaywrightNightly + vor Release2–5 min5–10
Dockerdocker-compose.testBei jedem PR1–2 min1 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

  1. https://www.guru99.com/regression-testing.html
  2. https://www.atlassian.com/continuous-delivery/software-testing/regression-testing
  3. 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.

Zurück zum DEV Blog
Share:

Ähnliche Beiträge