Debugging von Testfehlern¶
Wenn Tests fehlschlagen, müssen wir herausfinden, warum. Vielleicht liegt es am Test, vielleicht aber auch an der Anwendung. Der Prozess, um herauszufinden, wo das Problem liegt und was man dagegen tun kann, ist ähnlich.
pytest bietet viele Werkzeuge, die uns helfen können, ein Problem schneller zu
lösen, ohne dass wir zu einem Debugger greifen müssen. Python enthält einen
eingebauten Quellcode-Debugger namens pdb
, sowie mehrere Optionen, die das
Debuggen mit pdb
schnell und einfach machen.
Im Folgenden werden wir einige fehlerhafte Codes mit Hilfe von pytest-Optionen
und pdb
debuggen und uns dabei die Debugging-Optionen und die Integration
von pytest und pdb
anzusehen.
Debuggen mit pytest-Optionen¶
pytest enthält eine ganze Reihe von Kommandozeilen-Optionen, die für die Fehlersuche nützlich sind. Wir werden einige davon verwenden, um unsere Testfehler zu beheben. Optionen für die Auswahl, welche Tests in welcher Reihenfolge ausgeführt werden sollen und wann sie gestoppt werden sollen.
In all diesen Beschreibungen bezieht sich der Begriff Fehler auf eine fehlgeschlagene Assertion oder eine andere nicht abgefangene Exception, die in unserem Quell- oder Testcode, einschließlich der Fixtures, gefunden wurde.
Erneute Ausführung fehlgeschlagener Tests
Beginnen wir mit der Fehlersuche, indem wir sicherstellen, dass die Tests fehlschlagen, wenn wir sie erneut ausführen. Hierfür verwenden wir
--lf
, um nur die fehlgeschlagenen Tests erneut auszuführen, und--tb=no
, um den Traceback auszublenden. So wissen wir , dass wir den Fehler reproduzieren können.Nun können wir mit dem Debuggen des ersten Fehlers beginnen und führen hierzu den ersten fehlgeschlagenen Testaus, halten nach dem Fehler an und sehen uns den Traceback an:
pytest --lf -x
.Um sicher zu gehen, dass wir das Problem verstehen, können wir den gleichen Test mit
-l
/--showlocals
noch einmal durchführen. Wir brauchen den vollständigen Traceback nicht noch einmal, also können wir ihn mit--tb=short
kürzen:pytest --lf -x -l --tb=short
.-l
/--showlocals
sind oft sehr hilfreich und manchmal gut genug, um einen Testfehler vollständig zu erkennen.
Fehlersuche mit pdb
pdb ist Teil der Python Standardbibliothek, so dass wir nichts installieren müssen, um es zu benutzen. Ihr könnt pdb von pytest aus auf verschiedene Weise starten:
Fügt einen
breakpoint()
-Aufruf entweder zum Test- oder zum Anwendungscode hinzu. Wenn ein pytest Lauf auf einenbreakpoint()
-Funktionsaufruf trifft, wird er dort anhalten und pdb starten.Verwendet die
--pdb
-Option. Mit--pdb
hält pytest an der Stelle des Fehlers an.Verwendet die Kombination der
--lf
und--trace
-Optionen. Mit--trace
hält pytest am Anfang eines jeden Tests.Nachfolgend sind die üblichen Befehle aufgeführt, die von pdb erkannt werden:
Optionen
Beschreibung
Meta-Befehle
h(elp)
gibt eine Liste von Befehlen aus.
h(elp) COMMAND
gibt die Hilfe zu einem Befehl aus.
q(uit)
beendet pdb.
Sehen, wo ihr seid
l(ist)
listet elf Zeilen um die aktuelle Zeile auf; beim erneuten Aufruf werden die nächsten elf Zeilen aufgelistet.
l(ist) .
Das Gleiche wie oben, aber mit einem Punkt. Listet elf Zeilen um die aktuelle Zeile auf. Praktisch, wenn ihr
l(list)
ein paar Mal benutzt habt und eure aktuelle Position verloren habt.l(ist) first|last
listet eine bestimmte Gruppe von Zeilen auf.
ll
listet den gesamten Quellcode für die aktuelle Funktion auf.
w(here)
gibt den Stack-Trace aus.
Werte ansehen
p(rint) EXPR
wertet
EXPR
aus und gibt Wert aus.pp EXPR
entspricht
p(rint) EXPR
, verwendet aberpretty-print
aus dem pprint-Modul.a(rgs)
gibt die Argumentliste der aktuellen Funktion aus.
Ausführungsbefehle
s(tep)
führt die aktuelle Zeile aus und springt zur nächsten Zeile in Ihrem Quellcode, auch wenn sie sich innerhalb einer Funktion befindet.
n(ext)
führt die aktuelle Zeile aus und springt zur nächsten Zeile in der aktuellen Funktion.
c(ontinue)
wird bis zum nächsten Haltepunkt fortgesetzt. Bei Verwendung mit
--trace
bis zum Beginn des nächsten Tests fortgesetzt.unt(il) LINENO
wird bis zur angegebenen Zeilennummer fortgesetzt.
Siehe auch
Die vollständige Liste findet ihr in Debugger Commands der pdb-Dokumentation.
Kombinieren von pdb und tox¶
Um pdb mit tox kombinieren zu können, müssen wir sicherstellen, dass wir
Argumente durch tox an pytest übergeben können. Dies geschieht mit der
{posargs}
-Funktion von tox, die in pytest-Parameter an tox übergeben beschrieben wurde. Wir
haben diese Funktion bereits in unserer tox.ini
für Items eingerichtet:
[tox]
envlist = py38, py39, py310, py311
isolated_build = True
skip_missing_interpreters = True
[testenv]
deps =
pytest
faker
pytest-cov
commands = pytest --cov=items --cov-fail-under=99 {posargs}
[gh-actions]
python =
3.9: py39
3.10: py310
3.11: py311
3.12: py312
3.13: py313
Wir möchten die Python 3.13-Umgebung ausführen und den Debugger bei einem
fehlgeschlagenen Test starten mit tox -e py313 -- --pdb --no-cov
. Das
bringt uns in den pdb, genau an der Assertion, die fehlgeschlagen ist.
Nachdem wir den Fehler gefunden und behoben haben, können wir die Tox-Umgebung
mit diesem einen Testfehler erneut ausführen: tox -e py313 -- --lf --tb=no
--no-cov
.
Überblick über die gebräuchlichsten pytest-Debugger-Optionen¶
Optionen |
Beschreibung |
---|---|
Optionen für die Auswahl, welche Tests in welcher Reihenfolge ausgeführt werden sollen und wann sie gestoppt werden sollen: |
|
|
führt den zuerst fehlgeschlagenen Test aus |
|
startet mit dem zuerst fehlgeschlagenen Test und führt dann alle aus. |
|
hält beim ersten Fehler an und führt dann alle aus. |
|
stoppt die Tests nach |
|
führt zuerst neue Testdateien aus, dann den Rest sortiert nach Änderungsdatum. |
|
führt den letzten fehlgeschlagenen Test aus,
stoppt dann beim nächsten Fehler und startet
beim nächsten Mal wieder beim letzten
fehlgeschlagenen Test. Ähnlich wie die
Kombination von |
|
wie oben, aber ein fehlgeschlagener Test wird übersprungen. |
Optionen zur Kontrolle der pytest-Ausgabe: |
|
|
verbos, |
|
Traceback-Stil:
Üblicherweise nutze ich |
|
zeigt lokale Variablen neben dem Stacktrace an. |
Optionen zum Starten eines Kommandozeilen-Debuggers: |
|
|
startet den Python-Debugger im Fehlerfall. Sehr nützlich zum Debuggen mit tox. |
|
startet den pdb-Quellcode-Debugger sofort bei der Ausführung jedes Tests. |
|
verwendet Alternativen zu pdb, z.B. den IPython-Debugger mit
|