Wie fehlgeschlagene Tests erneut ausführen und den Zustand zwischen Testläufen beibehalten¶
Verwendung¶
Das Plugin bietet zwei Kommandozeilenoptionen, um Fehler aus dem letzten pytest Aufruf erneut auszuführen.
--lf,--last-failed- um nur die Fehler erneut auszuführen.--ff,--failed-first- um zuerst die Fehler und dann den Rest der Tests auszuführen.
Zur Bereinigung (normalerweise nicht erforderlich) ermöglicht die Option --cache-clear, alle Cross-Session-Cache-Inhalte vor einem Testlauf zu entfernen.
Andere Plugins können auf das config.cache Objekt zugreifen, um **JSON-kodierbare** Werte zwischen pytest Aufrufen festzulegen/abzurufen.
Hinweis
Dieses Plugin ist standardmäßig aktiviert, kann aber bei Bedarf deaktiviert werden: siehe Ein Plugin nach Namen deaktivieren / abmelden (der interne Name für dieses Plugin ist cacheprovider).
Fehler erneut ausführen oder Fehler zuerst ausführen¶
Erstellen wir zunächst 50 Testaufrufe, von denen nur 2 fehlschlagen.
# content of test_50.py
import pytest
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
pytest.fail("bad luck")
Wenn Sie dies zum ersten Mal ausführen, sehen Sie zwei Fehler.
$ pytest -q
.................F.......F........................ [100%]
================================= FAILURES =================================
_______________________________ test_num[17] _______________________________
i = 17
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:7: Failed
_______________________________ test_num[25] _______________________________
i = 25
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:7: Failed
========================= short test summary info ==========================
FAILED test_50.py::test_num[17] - Failed: bad luck
FAILED test_50.py::test_num[25] - Failed: bad luck
2 failed, 48 passed in 0.12s
Wenn Sie es dann mit --lf ausführen,
$ pytest --lf
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 2 items
run-last-failure: rerun previous 2 failures
test_50.py FF [100%]
================================= FAILURES =================================
_______________________________ test_num[17] _______________________________
i = 17
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:7: Failed
_______________________________ test_num[25] _______________________________
i = 25
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:7: Failed
========================= short test summary info ==========================
FAILED test_50.py::test_num[17] - Failed: bad luck
FAILED test_50.py::test_num[25] - Failed: bad luck
============================ 2 failed in 0.12s =============================
Sie haben nur die beiden fehlerhaften Tests aus dem letzten Lauf erneut ausgeführt, während die 48 bestandenen Tests nicht ausgeführt wurden ("deselektiert").
Wenn Sie nun mit der Option --ff ausführen, werden alle Tests ausgeführt, aber die ersten vorherigen Fehler werden zuerst ausgeführt (wie die Serie von FF und Punkten zeigt).
$ pytest --ff
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 50 items
run-last-failure: rerun previous 2 failures first
test_50.py FF................................................ [100%]
================================= FAILURES =================================
_______________________________ test_num[17] _______________________________
i = 17
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:7: Failed
_______________________________ test_num[25] _______________________________
i = 25
@pytest.mark.parametrize("i", range(50))
def test_num(i):
if i in (17, 25):
> pytest.fail("bad luck")
E Failed: bad luck
test_50.py:7: Failed
========================= short test summary info ==========================
FAILED test_50.py::test_num[17] - Failed: bad luck
FAILED test_50.py::test_num[25] - Failed: bad luck
======================= 2 failed, 48 passed in 0.12s =======================
Neue Optionen --nf, --new-first: Neue Tests zuerst ausführen, gefolgt vom Rest der Tests. In beiden Fällen werden die Tests auch nach der letzten Modifikationszeit der Datei sortiert, wobei neuere Dateien zuerst kommen.
Verhalten, wenn im letzten Lauf keine Tests fehlgeschlagen sind¶
Die Option --lfnf/--last-failed-no-failures steuert das Verhalten von --last-failed. Sie bestimmt, ob Tests ausgeführt werden, wenn es keine vorherigen (bekannten) Fehler gibt oder wenn keine zwischengespeicherten lastfailed Daten gefunden wurden.
Es gibt zwei Optionen:
all: Wenn keine Testfehler bekannt sind, werden alle Tests ausgeführt (die vollständige Testsuite). Dies ist die Standardeinstellung.none: Wenn keine Testfehler bekannt sind, wird lediglich eine Meldung ausgegeben und der Vorgang erfolgreich beendet.
Beispiel
pytest --last-failed --last-failed-no-failures all # runs the full test suite (default behavior)
pytest --last-failed --last-failed-no-failures none # runs no tests and exits successfully
Das neue config.cache Objekt¶
Plugins oder conftest.py-Supportcode können einen zwischengespeicherten Wert über das config Objekt von pytest abrufen. Hier ist ein einfaches Beispiel-Plugin, das eine Fixture implementiert, die den zuvor erstellten Zustand über pytest-Aufrufe hinweg wiederverwendet.
# content of test_caching.py
import pytest
def expensive_computation():
print("running expensive computation...")
@pytest.fixture
def mydata(pytestconfig):
val = pytestconfig.cache.get("example/value", None)
if val is None:
expensive_computation()
val = 42
pytestconfig.cache.set("example/value", val)
return val
def test_function(mydata):
assert mydata == 23
Wenn Sie diesen Befehl zum ersten Mal ausführen, sehen Sie die Print-Anweisung.
$ pytest -q
F [100%]
================================= FAILURES =================================
______________________________ test_function _______________________________
mydata = 42
def test_function(mydata):
> assert mydata == 23
E assert 42 == 23
test_caching.py:19: AssertionError
-------------------------- Captured stdout setup ---------------------------
running expensive computation...
========================= short test summary info ==========================
FAILED test_caching.py::test_function - assert 42 == 23
1 failed in 0.12s
Wenn Sie ihn ein zweites Mal ausführen, wird der Wert aus dem Cache abgerufen und nichts wird gedruckt.
$ pytest -q
F [100%]
================================= FAILURES =================================
______________________________ test_function _______________________________
mydata = 42
def test_function(mydata):
> assert mydata == 23
E assert 42 == 23
test_caching.py:19: AssertionError
========================= short test summary info ==========================
FAILED test_caching.py::test_function - assert 42 == 23
1 failed in 0.12s
Siehe die config.cache Fixture für weitere Details.
Cache-Inhalt inspizieren¶
Sie können den Inhalt des Caches jederzeit mit der Kommandozeilenoption --cache-show einsehen.
$ pytest --cache-show
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
cachedir: /home/sweet/project/.pytest_cache
--------------------------- cache values for '*' ---------------------------
cache/lastfailed contains:
{'test_caching.py::test_function': True}
cache/nodeids contains:
['test_caching.py::test_function']
example/value contains:
42
========================== no tests ran in 0.12s ===========================
--cache-show akzeptiert ein optionales Argument zur Angabe eines Glob-Musters für die Filterung.
$ pytest --cache-show example/*
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
cachedir: /home/sweet/project/.pytest_cache
----------------------- cache values for 'example/*' -----------------------
example/value contains:
42
========================== no tests ran in 0.12s ===========================
Cache-Inhalt löschen¶
Sie können pytest anweisen, alle Cache-Dateien und Werte zu löschen, indem Sie die Option --cache-clear wie folgt hinzufügen:
pytest --cache-clear
Dies wird für Aufrufe von Continuous Integration-Servern empfohlen, bei denen Isolation und Korrektheit wichtiger sind als Geschwindigkeit.
Stepwise¶
Als Alternative zu --lf -x, insbesondere für Fälle, in denen ein großer Teil der Testsuite fehlschlagen wird, ermöglicht --sw, --stepwise, die Behebung eines Fehlers nach dem anderen. Die Testsuite wird bis zum ersten Fehler ausgeführt und stoppt dann. Beim nächsten Aufruf wird ab dem letzten fehlerhaften Test fortgefahren und bis zum nächsten fehlerhaften Test ausgeführt. Sie können die Option --stepwise-skip verwenden, um einen fehlerhaften Test zu ignorieren und die Testausführung stattdessen beim zweiten fehlerhaften Test zu stoppen. Dies ist nützlich, wenn Sie bei einem fehlerhaften Test feststecken und ihn einfach bis später ignorieren möchten. Das Angeben von --stepwise-skip aktiviert auch implizit --stepwise.