如何重新執行失敗的測試並在測試執行之間維護狀態

用法

此外掛程式提供兩個命令列選項,用於重新執行上次 pytest 呼叫的失敗測試

  • --lf--last-failed - 僅重新執行失敗的測試。

  • --ff--failed-first - 先執行失敗的測試,然後執行其餘測試。

對於清理(通常不需要),--cache-clear 選項允許在測試執行之前移除所有跨工作階段快取內容。

其他外掛程式可以存取 config.cache 物件,以便在 pytest 呼叫之間設定/取得json 可編碼值。

注意

此外掛程式預設為啟用,但必要時可以停用:請參閱 依名稱停用/取消註冊外掛程式(此外掛程式的內部名稱為 cacheprovider)。

僅重新執行失敗的測試或先執行失敗的測試

首先,讓我們建立 50 個測試呼叫,其中只有 2 個會失敗

# 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")

如果您第一次執行此測試,您將會看到兩個失敗

$ 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

如果您接著使用 --lf 執行

$ pytest --lf
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.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 =============================

您只會執行上次執行中失敗的兩個測試,而 48 個通過的測試並未執行(「取消選取」)。

現在,如果您使用 --ff 選項執行,所有測試都將執行,但先前的失敗測試會先執行(可以從 FF 和點的系列中看出)

$ pytest --ff
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.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 =======================

新的 --nf--new-first 選項:先執行新的測試,然後執行其餘的測試,在這兩種情況下,測試也會依檔案修改時間排序,較新的檔案會先執行。

上次執行時沒有測試失敗時的行為

選項 --lfnf/--last-failed-no-failures 會控制 --last-failed 的行為。決定在沒有先前(已知)失敗或未找到快取的 lastfailed 資料時,是否執行測試。

有兩個選項

  • all:當沒有已知的測試失敗時,執行所有測試(完整的測試套件)。這是預設值。

  • none:當沒有已知的測試失敗時,只會發出訊息說明這一點,然後成功結束。

範例

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

新的 config.cache 物件

外掛程式或 conftest.py 支援程式碼可以使用 pytest config 物件取得快取值。以下是實作 固定裝置 的基本範例外掛程式,它會在 pytest 呼叫中重複使用先前建立的狀態

# 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

如果你第一次執行此指令,可以看到列印陳述式

$ 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

如果你第二次執行它,值會從快取中擷取,且不會列印任何內容

$ 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

請參閱 config.cache 固定裝置 以取得更多詳細資料。

檢查快取內容

你可以隨時使用 --cache-show 命令列選項來窺探快取的內容

$ pytest --cache-show
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.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']
cache/stepwise contains:
  []
example/value contains:
  42

========================== no tests ran in 0.12s ===========================

--cache-show 會採用一個選用引數來指定用於篩選的 glob 模式

$ pytest --cache-show example/*
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.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 ===========================

清除快取內容

你可以指示 pytest 清除所有快取檔案和值,方法是像這樣加入 --cache-clear 選項

pytest --cache-clear

建議在隔離和正確性比速度更重要的持續整合伺服器上進行呼叫。

逐步

作為 --lf -x 的替代方案,特別是在您預期測試套件的大部分會失敗的情況下,--sw--stepwise 允許您一次修復一個。測試套件將執行到第一次失敗,然後停止。在下一次呼叫時,測試將從上次失敗的測試繼續,然後執行到下一個失敗的測試。您可以使用 --stepwise-skip 選項來忽略一個失敗的測試,而是在第二個失敗的測試上停止測試執行。如果您遇到失敗的測試而卡住,只想在稍後再忽略它,這會很有用。提供 --stepwise-skip 也會隱含啟用 --stepwise