| name | testing-python-pytest |
| description | Generates professional pytest unit test suites for Python source files, ensuring >90% line and branch coverage per file. Analyzes modules with AST inspection to discover all classes, methods, and functions, then produces well-structured tests following the AAA pattern with fixtures, parametrize, mocking, and comprehensive edge cases. Use when asked to write unit tests, create a test suite, generate pytest tests, improve coverage, or test Python modules, classes, or functions — even if the user does not explicitly mention "pytest" or "coverage". Also use when CI pipelines report low test coverage.
|
| compatibility | Requires Python >=3.8 and pip install pytest pytest-cov pytest-mock |
| license | MIT |
| metadata | {"author":"skill-creator","version":"1.1"} |
| allowed-tools | Bash Read Write |
Python pytest Test Suite Generator
Generates comprehensive, production-quality pytest unit test suites that
achieve >90% line and branch coverage per file.
Quick start
pip install pytest pytest-cov pytest-mock
python scripts/analyze_module.py src/my_module.py
python scripts/run_coverage.py src/my_module.py tests/test_my_module.py
Workflow
Kopiere diese Checkliste und hake ab:
Testing Progress:
- [ ] Step 1: Modul analysieren → analyze_module.py
- [ ] Step 2: Testdatei schreiben → AAA, Fixtures, Parametrize, Mocks
- [ ] Step 3: Coverage messen → run_coverage.py
- [ ] Step 4: Lücken schließen → Fehlende Zweige gezielt testen
- [ ] Step 5: ≥90 % bestätigt → Fertig ✓
Step 1 — Modul analysieren
python scripts/analyze_module.py <pfad/zum/modul.py>
Das Script gibt JSON aus mit: Klassen, Methoden, Funktionen, Typ-Hinweisen,
Exception-Pfaden, Async-Code und konkreten Testing-Hints.
Step 2 — Testdatei schreiben
Dateiname: tests/test_<modulname>.py
Lese references/PYTEST_PATTERNS.md für
Fixtures, Parametrize, Mocking und Async-Tests.
Struktur jeder Testfunktion — AAA-Pflicht:
def test_<methode>_<szenario>(self, fixture):
input_val = ...
result = unit_under_test(input_val)
assert result == expected
Mindestabdeckung pro Einheit:
| Szenario | Pflicht |
|---|
| Happy path (Normalfall) | ✓ |
| Grenzwerte (0, -1, leer, None) | ✓ |
Exception-Pfade (pytest.raises) | ✓ je raise im Code |
Alle Bedingungszweige (if/else) | ✓ |
| Externe Abhängigkeiten gemockt | ✓ |
Step 3 & 4 — Coverage messen und Lücken schließen
python scripts/run_coverage.py <modul_pfad> <testdatei_pfad>
Das Script gibt aus: Gesamtabdeckung, nicht abgedeckte Zeilen, ob
der 90 %-Threshold erreicht wurde, und konkrete Empfehlungen.
Feedback-Schleife:
- Uncovered lines lesen → betroffene Zeile im Quellcode finden
- Welcher Branch/Condition ist nicht abgedeckt?
- Gezielten Test hinzufügen → erneut messen
- Wiederholen bis ≥90 %
Step 5 — Abnahme
Coverage-Report zeigt ≥90 % für Zieldatei → Skill beendet.
Test-Datei Musterstruktur
"""Tests for <module_name>."""
import pytest
from unittest.mock import patch, MagicMock, call, ANY
from <package>.<module> import <ClassName>, <function_name>
@pytest.fixture
def default_instance():
"""Standard-Instanz für Tests."""
return <ClassName>(param="default")
@pytest.fixture
def mock_dependency(mocker):
"""Gemockte externe Abhängigkeit."""
return mocker.patch("<package>.<module>.<ExternalClass>")
class Test<ClassName>:
"""Tests für <ClassName>."""
def test_init_sets_defaults(self):
obj = <ClassName>()
assert obj.attr == expected_default
def test_<method>_returns_expected(self, default_instance):
...
result = default_instance.<method>(...)
assert result == expected
@pytest.mark.parametrize("input,expected", [
("valid", True),
("", False),
(None, False),
])
def test_<method>_parametrized(self, default_instance, input, expected):
assert default_instance.<method>(input) == expected
def test_<method>_raises_value_error_on_none(self, default_instance):
with pytest.raises(ValueError, match="must not be None"):
default_instance.<method>(None)
def test_<method>_calls_dependency(self, default_instance, mock_dependency):
default_instance.<method>("arg")
mock_dependency.assert_called_once_with("arg")
class Test<FunctionName>:
def test_happy_path(self):
assert <function_name>("valid") == expected
def test_empty_input(self):
assert <function_name>("") == []
def test_raises_on_invalid_type(self):
with pytest.raises(TypeError):
<function_name>(42)
Coverage-Anforderungen
| Metrik | Minimum |
|---|
| Zeilenabdeckung (je Datei) | ≥ 90 % |
| Branch-Abdeckung | ≥ 85 % |
| Öffentliche Methoden mit Test | 100 % |
| Exception-Pfade getestet | 100 % |
Verfügbare Scripts
scripts/analyze_module.py — AST-Analyse einer Python-Datei → JSON
scripts/run_coverage.py — pytest + Coverage ausführen → JSON + Report
Referenzen