Claude Code Pytest: Tests schreiben, Fixtures aufsetzen, Coverage messen
Testing gehört zu den Aufgaben, die Entwickler am häufigsten aufschieben — nicht weil sie unwichtig wären, sondern weil das Aufsetzen einer sauberen Test-Infrastruktur Zeit kostet. Fixtures einrichten, Mocks konfigurieren, Coverage-Reports interpretieren: All das kommt on top, wenn eigentlich schon die eigentliche Feature-Arbeit wartet.
Claude Code Pytest verändert diese Gleichung. Statt Boilerplate von Hand zu schreiben, beschreibst du was du testen willst — und Claude Code generiert die Test-Datei, richtet die Fixtures ein und findet Edge-Cases, die du vielleicht übersehen hättest. Dieser Artikel zeigt, wie das konkret funktioniert.
Claude Code Mastery — Testing, Agents, Hooks auf Deutsch
Nicht nur Pytest: der Kurs zeigt, wie du Claude Code wirklich produktiv einsetzt — von automatisierten Tests über Debugging bis zu autonomen Workflows. Einmalig bezahlt, kein Abo.
Zum Kurs — Jetzt starten → Einmalzahlung · Kein Abo · 14 Tage Rückgaberecht1. Was ist Pytest — und warum es der Standard ist
Pytest ist Pythons meistgenutztes Testing-Framework. Im Vergleich zum eingebauten unittest-Modul punktet es vor allem durch seine klare Syntax: kein Erben von Testklassen, keine umständlichen self.assert*-Methoden — stattdessen einfache assert-Statements, die Python-nativ sind.
# Einfachster pytest-Test
def test_addition():
assert 1 + 1 == 2
def test_string_upper():
assert "hallo".upper() == "HALLO"
Pytest erkennt alle Dateien, die mit test_ beginnen oder auf _test.py enden, und alle Funktionen darin, die mit test_ starten. Kein Setup, keine Konfiguration für den Einstieg. Das macht es zum bevorzugten Werkzeug für Python-Projekte jeder Größe — von kleinen Skripten bis zu Django-Anwendungen.
Installation: pip install pytest reicht für den Start. Für Coverage kommt pip install pytest-cov dazu, für Mocking-Unterstützung pip install pytest-mock.
2. Teststruktur: Dateien, assert-Statements, Testklassen
Eine saubere Teststruktur erleichtert die Navigation und verhindert, dass Tests sich gegenseitig beeinflussen. Die Konvention: ein tests/-Verzeichnis auf der gleichen Ebene wie der Quellcode, mit Dateien die die Struktur des Projekts spiegeln.
mein-projekt/
src/
rechner.py
api/
users.py
tests/
test_rechner.py
api/
test_users.py
Testklassen sind optional — sie bieten sich an, wenn mehrere Tests denselben Kontext teilen:
class TestRechner:
def test_addition(self):
assert rechner.addiere(2, 3) == 5
def test_division_durch_null(self):
with pytest.raises(ZeroDivisionError):
rechner.dividiere(10, 0)
Das pytest.raises-Kontextmanager ist besonders wertvoll: Er testet nicht nur, ob eine Exception geworfen wird, sondern auch ob es die richtige ist. Ein fehlendes raises-Test ist einer der häufigsten Lücken in Python-Test-Suites.
3. Fixtures: @pytest.fixture und conftest.py
Fixtures sind der Kern von Pytest. Sie liefern Testdaten, Datenbankverbindungen, temporäre Dateien oder andere Abhängigkeiten — und stellen sicher, dass jeder Test in einem definierten Zustand startet.
import pytest
@pytest.fixture
def beispiel_nutzer():
return {"id": 1, "name": "Anna", "email": "anna@beispiel.de"}
def test_nutzer_name(beispiel_nutzer):
assert beispiel_nutzer["name"] == "Anna"
Der scope-Parameter steuert, wie lange eine Fixture lebt:
- function (Standard): neue Instanz für jeden Test
- class: eine Instanz für alle Tests in einer Klasse
- module: eine Instanz für alle Tests in einer Datei
- session: eine Instanz für die gesamte Test-Session
@pytest.fixture(scope="session")
def db_verbindung():
conn = datenbank.verbinden("sqlite:///:memory:")
datenbank.schema_erstellen(conn)
yield conn
conn.schliessen()
Das yield-Muster ist wichtig: alles vor yield ist Setup, alles danach ist Teardown. Pytest führt den Teardown auch dann aus, wenn ein Test fehlschlägt.
Fixtures die in mehreren Dateien gebraucht werden, gehören in conftest.py — eine spezielle Datei, die Pytest automatisch lädt:
# tests/conftest.py
@pytest.fixture(scope="session")
def app_config():
return {"debug": False, "testing": True, "datenbank": "sqlite:///:memory:"}
4. Parametrisierung: @pytest.mark.parametrize
Statt denselben Test zehnmal mit verschiedenen Werten zu kopieren, nutzt man parametrize. Das hält die Tests kompakt und macht es einfach, neue Fälle hinzuzufügen:
@pytest.mark.parametrize("eingabe,erwartet", [
("hallo", "HALLO"),
("welt", "WELT"),
("", ""),
("123abc", "123ABC"),
])
def test_grossschreibung(eingabe, erwartet):
assert eingabe.upper() == erwartet
Pytest zeigt bei Fehlern genau welche Parameterkombination gescheitert ist — das beschleunigt die Fehlersuche erheblich. Für komplexere Fälle lassen sich Parametrize-Dekoratoren stapeln, was eine Matrix von Testfällen erzeugt.
5. Mocking: unittest.mock, pytest-mock und monkeypatch
Tests sollen isoliert laufen — ohne echte Datenbankverbindungen, API-Aufrufe oder Filesystem-Operationen. Dafür gibt es Mocking.
unittest.mock
from unittest.mock import patch, MagicMock
def test_api_aufruf():
with patch("mein_modul.requests.get") as mock_get:
mock_get.return_value.json.return_value = {"status": "ok"}
mock_get.return_value.status_code = 200
ergebnis = mein_modul.nutzer_laden(1)
assert ergebnis["status"] == "ok"
mock_get.assert_called_once()
pytest-mock (empfohlen)
pytest-mock stellt die mocker-Fixture bereit, die sauberer zu schreiben ist:
def test_api_aufruf(mocker):
mock_get = mocker.patch("mein_modul.requests.get")
mock_get.return_value.json.return_value = {"status": "ok"}
ergebnis = mein_modul.nutzer_laden(1)
assert ergebnis["status"] == "ok"
monkeypatch
Pytest's eingebautes monkeypatch ist ideal für Umgebungsvariablen, Konfigurationswerte oder einfache Attribut-Ersetzungen:
def test_mit_umgebungsvariable(monkeypatch):
monkeypatch.setenv("API_KEY", "test-schluessel-123")
monkeypatch.setattr(config, "timeout", 30)
ergebnis = mein_dienst.initialisieren()
assert ergebnis.konfiguriert is True
Wichtig beim Mocking: Immer den Pfad mocken, wo das Objekt benutzt wird, nicht wo es definiert ist. Statt patch("requests.get") also patch("mein_modul.requests.get"). Das ist die häufigste Fehlerquelle beim Einstieg in Mocking.
6. Coverage: pytest-cov und Coverage-Gaps finden
Eine hohe Test-Coverage gibt Sicherheit bei Refactorings und macht Bugs sichtbar bevor sie in Production gehen. pytest-cov integriert Coverage-Messung direkt in den pytest-Lauf:
# Coverage für ein Modul messen
pytest --cov=src tests/
# HTML-Report generieren
pytest --cov=src --cov-report=html tests/
# Fehlende Zeilen direkt im Terminal anzeigen
pytest --cov=src --cov-report=term-missing tests/
Der HTML-Report unter htmlcov/index.html zeigt exakt welche Zeilen und Branches noch nicht getestet sind. Besonders wertvoll: die Branch-Coverage zeigt nicht nur ob eine Zeile ausgeführt wurde, sondern ob alle Verzweigungen (beide Pfade eines if/else) abgedeckt sind.
# Branch-Coverage aktivieren
pytest --cov=src --cov-branch --cov-report=term-missing tests/
Eine sinnvolle Mindestgrenze setzen und in CI erzwingen:
# pytest.ini oder pyproject.toml
[tool.pytest.ini_options]
addopts = "--cov=src --cov-fail-under=80"
7. Claude Code Pytest: So beschleunigt Claude Code deinen Test-Workflow
Jetzt kommt der entscheidende Teil: wie Claude Code Pytest-Arbeit konkret verändert.
Tests für bestehenden Code generieren
Der häufigste Anwendungsfall — Legacy-Code hat keine Tests, und man weiß nicht wo anfangen:
claude "Schreib pytest-Tests für src/services/bestellungen.py.
Decke die Hauptpfade ab, Fehlerfälle, und Edge-Cases bei leerer
Bestellliste. Nutze Fixtures für Testdaten."
Claude Code liest die Datei, analysiert alle Methoden und ihre möglichen Zustände, und schreibt eine vollständige Test-Datei mit sinnvollen Testfällen — inklusive Fixtures für die Testdaten und Mocks für externe Abhängigkeiten.
Fixtures für komplexe Setups aufsetzen
claude "Erstelle eine conftest.py mit Fixtures für unsere Django-Tests:
Datenbankverbindung mit session scope, einen authentifizierten Test-Client,
und Beispieldaten für User, Produkte und Bestellungen."
Edge-Cases identifizieren
"Analysiere meine Funktion berechne_rabatt() in pricing.py und liste alle Edge-Cases auf, die ich testen sollte. Dann schreib die Tests dafür mit parametrize."
Claude Code findet Fälle, die man selbst übersieht: negative Werte, Werte genau an Grenzen, leere Listen, None-Werte, sehr große Zahlen, Unicode-Strings. Das Ergebnis ist eine parametrisierte Test-Suite, die auch unerwartete Eingaben abdeckt.
Coverage-Gaps schließen
pytest --cov=src --cov-report=term-missing tests/ 2>&1 | \
claude "Welche Codepfade sind noch nicht getestet?
Schreib Tests für die fehlenden Zeilen."
Claude Code liest den Coverage-Report, identifiziert die unbetesteten Pfade und schreibt gezielt Tests dafür — oft inklusive dem richtigen Mocking-Setup, damit auch schwer erreichbare Codepfade (Fehlerbehandlung, Timeouts, Netzwerkfehler) getestet werden können.
- Test-Boilerplate: Von Hand — 30–60 Minuten für ein neues Modul. Mit Claude Code — unter 5 Minuten.
- Edge-Cases: Menschen denken an 5–10 Fälle. Claude Code findet routinemäßig 20–30.
- Fixture-Setup: Datenbankfixtures, Session-Scoping, Teardown — das sind Stunden Arbeit. Claude Code macht es in Minuten korrekt.
Zwei verwandte Artikel, die auf diesem Thema aufbauen:
- Claude Code Debugging — Bugs finden und Root-Cause analysieren mit Claude Code
- Claude Code für Python-Projekte — der gesamte Python-Workflow mit Claude Code
Claude Code Mastery — von Pytest bis zum produktiven Agenten
Testing ist eine Stärke von Claude Code — aber nicht die einzige. Im Kurs lernst du Agents, MCP-Server, Hooks, Multi-Agent-Workflows und mehr. Vollständig auf Deutsch, einmalig bezahlt.
Jetzt starten → Einmalzahlung · Kein Abo · 14 Tage RückgaberechtKurs · Claude Code Mastery
Von Pytest zum produktiven AI-Agenten
Testing. Debugging. Agents. MCP. Hooks. Alles auf Deutsch, einmalig bezahlt — kein Abo, keine Plattformabhängigkeit.
Einmalzahlung · Kein Abo · 14 Tage Rückgaberecht