Ein pytest-Lauf kann mit bestandenen Tests enden, obwohl die Zahl der Warnungen von Lauf zu Lauf steigt. DeprecationWarning-Einträge weisen beispielsweise auf API-Aufrufe hin, die bei einem späteren Bibliothekswechsel angepasst werden müssen. Die Tests bleiben trotzdem grün. pytest 9.1 kann die Zahl der Warnungen mit --max-warnings begrenzen. Ein Warning-Budget taugt als CI-Regel nur mit einer gemessenen Baseline: Ein frei gewählter Grenzwert zeigt zwar eine Überschreitung an, sagt aber nichts über die Ursachen der vorhandenen Warnungen.
Warum bestandene Tests nicht ausreichen
pytest unterscheidet zwischen fehlgeschlagenen Tests und Warnungen, die während eines Testlaufs entstehen. Ohne Warnungsgrenze bleibt ein Lauf mit bestandenen Tests erfolgreich, selbst wenn Bibliotheken oder der eigene Code DeprecationWarning-Einträge ausgeben. Die Warnungen stehen nur in der Ausgabe. Liest das Team das Protokoll erst bei roten CI-Läufen, fällt ein wachsender Warnungsbestand womöglich erst beim nächsten Upgrade auf.
Zehn Einträge können auf denselben veralteten Aufruf zurückgehen; eine einzige neue Meldung aus einer anderen Bibliothek hat dagegen eine eigene Ursache. Die Zahl zeigt Veränderungen an. Um den nächsten Anstieg zu verstehen, braucht das Team neben der Gesamtzahl auch die Meldungen und ihre Fundstellen. Deshalb beginnt das Budget mit einem Testlauf unter denselben Bedingungen wie in der CI.
Aktuelle Warnungen messen und nach Ursache gruppieren
Andere Paketversionen können die Warnungszahl verändern. Für die Baseline läuft die vollständige Testsuite deshalb mit demselben Python-Interpreter, denselben installierten Abhängigkeiten und derselben pytest-Konfiguration wie in der CI. Beim ersten Lauf bleibt das Limit noch aus.
python -m pytest
Die Testzusammenfassung nennt die Warnungszahl. Im Warnungsüberblick zeigen Typ, Meldung und Fundstelle, ob mehrere Einträge auf denselben Aufruf zurückgehen. Wer nur die Gesamtzahl notiert, kann einen neuen Hinweis später schwer von einem bekannten unterscheiden, der häufiger auftritt.
- Eine DeprecationWarning mit Fundstelle im eigenen Code kann auf einen veralteten API-Aufruf hinweisen
- Eine ResourceWarning kann auf eine Datei oder Verbindung hinweisen, die ein Test nicht schließt
- Bei Warnungen aus Abhängigkeiten lohnt ein Blick auf die Paketversion und den auslösenden Aufruf
Durch das Gruppieren werden zehn gleichartige Meldungen nicht mit zehn unabhängigen Ursachen verwechselt. Weitere Themen rund um Softwaretests findest du in der Übersicht der Software-Testing-Seminare. Für das Warning-Budget liefert die gemessene Gesamtzahl nun den ersten Grenzwert.
Ein Warning-Budget in pytest 9.1 setzen
Zehn ist hier nur ein Beispielwert und keine Empfehlung für Python-Projekte. Über die Kommandozeile gilt die Grenze für diesen Testlauf.
python -m pytest --max-warnings=10
Wie funktioniert ein Warning-Budget in pytest?
pytest 9.1 vergleicht die Zahl der nicht gefilterten Warnungen eines Testlaufs mit einer festgelegten Obergrenze. Du setzt sie über --max-warnings oder den Eintrag max_warnings in der pytest.ini. Bei bestandenen Tests und überschrittenem Limit endet der Lauf mit Exit-Code 6; bis zur Grenze entscheidet das Testergebnis über den Exit-Code.
Liegt die gemessene Baseline bei 14 Warnungen, würde ein Limit von zehn die CI sofort scheitern lassen. Vier Warnungen liegen darüber. Ein anfängliches Limit von 14 hält den bestehenden Stand fest, ohne neue Warnungen zuzulassen. Genau am Limit bleibt der Testlauf innerhalb des Budgets; nach der Behebung von vier Warnungen lässt sich die Grenze auf zehn senken.
Soll der Grenzwert für lokale Läufe und CI gleichermaßen gelten, steht er als max_warnings in der pytest.ini. Dann liest pytest die Projekteinstellung auch bei python -m pytest.
[pytest]
max_warnings = 14
Der Grenzwert gilt damit beim lokalen Testlauf und im CI-Job. Ob die Pipeline einen Testfehler oder eine Limitüberschreitung meldet, zeigt der Exit-Code.
Exit-Code 6 in der CI richtig behandeln
Bei bestandenen Tests und überschrittenem Limit liefert pytest Exit-Code 6. Schlagen Tests fehl, liefert pytest stattdessen Exit-Code 1, auch wenn zugleich zu viele Warnungen auftreten. Eine CI-Auswertung, die beide Fälle pauschal als „Tests fehlgeschlagen“ meldet, verdeckt den Unterschied zwischen einem Testfehler und einem überschrittenen Warning-Budget.
Ein Shell-Schritt kann den Status auswerten und unverändert an die CI zurückgeben. Innerhalb der if-Bedingung bricht eine Shell mit set -e nicht vor der Auswertung des Nicht-Null-Status ab. Im Beispiel liest pytest den Grenzwert aus der pytest.ini.
if python -m pytest; then
echo "Testlauf erfolgreich"
else
status=$?
case "$status" in
1) echo "Tests fehlgeschlagen" ;;
6) echo "Warning-Budget überschritten" ;;
*) echo "pytest Exit-Code: $status" ;;
esac
exit "$status"
fi
Ein Warnungsfilter verändert die Zahl, gegen die pytest das Budget prüft; ignorierte Warnungen zählen nicht. Ein neues Ignore-Muster kann eine Limitüberschreitung daher verdecken, ohne deren Ursache zu beheben. Das ist besonders relevant, wenn Abhängigkeiten Warnungen ausgeben und das Team über Ausnahmen nachdenkt.
Das Budget senken, ohne Ursachen zu verstecken
Bei einer DeprecationWarning mit Fundstelle im eigenen Paket lässt sich der veraltete API-Aufruf ersetzen und anschließend der betroffene Test erneut ausführen. Eine ResourceWarning verlangt dagegen einen Blick auf den Test, der eine Datei oder Verbindung offenlässt. Warnungstyp und Fundstelle bestimmen die Korrektur. Die Position der Meldung in der Ausgabe sagt darüber nichts aus.
Nach der Korrektur zählt ein vollständiger Testlauf erneut. Sinkt die Zahl von 14 auf zehn Warnungen, wird max_warnings auf zehn gesetzt. Dadurch löst die Rückkehr einer der behobenen Warnungen wieder eine Limitüberschreitung aus.
Bei einer bekannten Warnung aus einem fremden Paket lässt sich eine vorübergehende Ausnahme auf die betreffende Meldung und ihren Ursprung begrenzen. Ein pauschales Ignorieren aller DeprecationWarning-Einträge würde hingegen auch neue Hinweise aus dem eigenen Paket aus dem Budget entfernen. Nach einem Paket-Upgrade zeigt ein erneuter Testlauf, ob die Ausnahme noch gebraucht wird. Die verbleibenden Meldungen liefern dann den Ausgangspunkt für die nächste Absenkung.
Fazit: Den nächsten Grenzwert aus dem Testlauf ableiten
Ein Grenzwert aus dem vollständigen Testlauf macht neue Warnungen sichtbar, ohne den vorhandenen Bestand sofort zum CI-Fehler zu machen. Starte mit einem Lauf ohne Limit und setze max_warnings erst nach Sichtung der Meldungen auf die gemessene Warnungszahl.