Table of Contents
Motivation
Tests sind ein zentraler Bestandteil moderner Entwicklung. Das Framework pytest macht das Schreiben, Organisieren und Ausführen von Tests einfach, flexibel und leistungsfähig.
Tests schreiben und ausführen
Installation
Zuerst installierst du pytest mit:
pip install pytest
pytest ist kompatibel mit unittest-Tests und erfordert keine Testklassen.
Namenskonventionen
Damit pytest Tests automatisch findet, müssen Dateien und Funktionen bestimmte Namen haben:
- Dateinamen haben test im Namen
- Funktionsnamen beginnen mit test_
Beispiel:
def test_example():
x = 5
assert x == 5
Mit pytest im Terminal führt pytest alle passenden Tests aus.
Testauswahl
Du kannst gezielt Tests ausführen:
pytest test_module.py::test_function
pytest -k "keyword"
Optionen wie -v (verbose), -x (bei Fehler abbrechen) oder -s (print-Ausgaben anzeigen) sind sehr praktisch.
Um Optionen nicht immer per Hand eingeben zu müssen, können diese auch in einer pytest.ini angegeben werden:
[pytest]
pythonpath = .
addopts = -x --durations=0 -vv
Fortgeschrittene pytest-Techniken
Fixtures
import pytest
@pytest.fixture(scope="function")
def simple_fixture():
return 42
def test_function(simple_fixture):
assert simple_fixture == 42
Fixture scopes
pytest-Fixtures haben einen Scope, der bestimmt, wie oft eine Fixture erzeugt und wiederverwendet wird.
Der Standard-Scope ist function, d. h. die Fixture wird für jeden Test neu ausgeführt.
Weitere Scopes sind:
- class – einmal pro Testklasse
- module – einmal pro Datei
- package – einmal pro Paket
- session – einmal pro gesamtem Testlauf
Größere Scopes verbessern die Performance, bergen aber das Risiko von geteiltem Zustand zwischen Tests.
Daher gilt: so klein wie möglich, so groß wie nötig.
Setup and teardown
Mit pytest können wir klassische setup / teardown Methoden mit fixtures nachbauen
import pytest
def test_setup_and_teardown():
assert True
@pytest.fixture(autouse=True, scope="function")
def setup_and_teardown():
print("SetUp")
# setup code goes here
yield
print("TearDown")
# teardown code goes here
Parametrisierung
Mit Parametrisierung lässt sich derselbe Test mit verschiedenen Daten ausführen. So umgehst du Duplikate:
import pytest
@pytest.mark.parametrize("data, expected", [
([1], 1),
([1, 2], 1.5),
([1, 2, 3], 2),
])
def test_calculate_mean(data, expected_mean):
mean = calculate_mean(data)
assert mean == expected_mean
def calculate_mean(data):
return sum(data) / len(data)
Das definiert mehrere Testinstanzen automatisch.
Marker
Marker helfen, Gruppen von Tests zu steuern.
Marker eignen sich z. B. zur Gruppierung nach Plattform, Kategorie oder Dauer.
Es gibt drei eingebaute Marker:
- skip
- skipif
- xfail
import pytest
import sys
@pytest.mark.skip(reason="Feature not yet implemented")
def test_future():
pass
@pytest.mark.skipif(sys.platform == "win32", reason="Linux only")
def test_linux_only():
pass
@pytest.mark.xfail(reason="Bug #123")
def test_known_bug():
pass
Eigene Marker
import pytest
@pytest.mark.slow
def test_slow():
pass
In pytest.ini:
[pytest]
...
markers =
slow: mark slow tests
Dann kannst du testen mit:
pytest -m slow
Oder alle nicht langsamen Tests laufen lassen:
pytest -m "not slow"
Nahezu gleiche Vergleiche
Für Fließkommazahlen ist ein exakter Vergleich oft ungeeignet. pytest bietet das approx-Feature:
assert 2.2 == pytest.approx(2.3, 0.1)
Erlaubt eine Toleranz statt exakter Übereinstimmung.
Exceptions testen
Mit pytest kannst du das Auftreten von Ausnahmen elegant testen:
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
Das prüft, ob ein Fehler erwartet korrekt geworfen wird.
Test-Reporting & Coverage
Testabdeckung mit pytest-cov
Mit dem Plugin pytest-cov lässt sich messen, wie viel deines Codes getestet wird:
pip install pytest-cov
pytest --cov=my_app 10_app_test
Ergebnis: Coverage-Statistiken zeigen an, wie viele Zeilen getestet wurden.
HTML-Reports
Du kannst mit demselben Plugin HTML-Berichte erzeugen:
pytest --cov=my_app --cov-report=html
Eine visuelle Übersicht über die Abdeckung hilft bei der Analyse.
Integration mit Werkzeugen
Coverage-Daten lassen sich in Tools wie SonarQube einbinden:
pytest --cov-report=xml:coverage.xml
Dadurch kannst du Metriken in CI/CD-Pipelines oder Dashboards verwenden.
Assertions mit Hamcrest (optional, aber mächtig)
Neben den eingebauten assert-Anweisungen von pytest kann man auch Hamcrest verwenden.
Hamcrest ist eine Matcher-Bibliothek, die Tests lesbarer und ausdrucksstärker machen kann – besonders bei komplexen Datenstrukturen.
Installation
pip install pyhamcrest
Import in Tests:
from hamcrest import assert_that, equal_to
Warum Hamcrest?
Vergleich:
def test_hamcrest_assert():
result = 42
assert_that(result, equal_to(42))
Der Vorteil zeigt sich bei komplexeren Assertions:
def test_hamcrest_start_with():
name = "Max Mustermann"
assert_that(name, starts_with("Max"))
def test_hamcrest_has_length():
items: Sized = ['apple', 'banana', 'cherry']
assert_that(items, has_length(3))
Tests lesen sich mehr wie Spezifikationen.
Listen & Collections
from hamcrest import assert_that, has_items
from collections.abc import Sequence
def test_compare_list_of_items():
actual_list_of_items: Sequence[str] = ['apple', 'banana', 'cherry']
assert_that(actual_list_of_items, has_items("apple", "banana"))
Fazit
pytest ist ein einfaches, doch mächtiges Framework zur Testautomatisierung in Python. Es kombiniert:
- geringe Einstiegshürde – einfache Tests schnell geschrieben
- hohe Flexibilität – Marker, Parameter, Coverage
- gute Tools-Integration – HTML-Reports oder CI-Coverage
Damit eignet es sich sowohl für Einsteiger als auch für professionelle Test-Pipelines.






