Spec-Zone.ru › pytest

Как повторно запускать неудачные тесты и сохранять состояние между запусками тестов

Использование

Плагин предоставляет два параметра командной строки для повторного запуска ошибок из последнего вызова pytest:

  • --lf, --last-failed — для повторного запуска только неудачных тестов.
  • --ff, --failed-first — чтобы сначала запустить неудачные тесты, а затем остальные.

Для очистки (обычно не требуется) параметр --cache-clear позволяет удалить всё содержимое кэша между сеансами перед запуском тестов.

Другие плагины могут обращаться к объекту config.cache, чтобы задавать и получать значения, кодируемые в JSON, между вызовами pytest.

Примечание

Этот плагин включён по умолчанию, но при необходимости его можно отключить: см. Деактивация / отмена регистрации плагина по имени (внутреннее имя этого плагина — 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-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 =============================

Вы запустили только два теста, завершившихся неудачно при последнем запуске, а 48 успешно пройденных тестов не запускались («исключены из выбора»).

Если запустить тесты с параметром --ff, будут выполнены все тесты, но сначала запустятся тесты, завершившиеся неудачно в прошлый раз (это видно по последовательности FF и точек):

$ 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 =======================

Новый параметр --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):
    cache = getattr(pytestconfig, "cache", None)
    if cache is None:
        # pytestconfig not having the cache attribute means the
        # cache plugin is disabled.
        expensive_computation()
        return 42

    val = cache.get("example/value", None)
    if val is None:
        expensive_computation()
        val = 42
        cache.set("example/value", val)
    return val


def test_function(mydata):
    assert mydata == 23

При первом запуске этой команды вы увидите вывод инструкции print:

$ pytest -q
F                                                                    [100%]
================================= FAILURES =================================
______________________________ test_function _______________________________

mydata = 42

    def test_function(mydata):
>       assert mydata == 23
E       assert 42 == 23

test_caching.py:26: 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:26: AssertionError
========================= short test summary info ==========================
FAILED test_caching.py::test_function - assert 42 == 23
1 failed in 0.12s

Подробнее см. в разделе config.cache fixture.

Просмотр содержимого кэша

Вы всегда можете посмотреть содержимое кэша с помощью параметра командной строки --cache-show:

$ 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 принимает необязательный аргумент — шаблон glob для фильтрации:

$ 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-clear следующим образом:

pytest --cache-clear

Это рекомендуется для запусков на серверах непрерывной интеграции, где изоляция и корректность важнее скорости.

Пошаговый запуск

В качестве альтернативы параметрам --lf -x, особенно если ожидается, что значительная часть набора тестов завершится неудачно, параметр --sw, --stepwise позволяет исправлять ошибки по одной. Набор тестов будет выполняться до первой ошибки, после чего запуск остановится. При следующем запуске тестирование продолжится с последнего теста, завершившегося неудачно, и будет идти до следующей ошибки. С помощью параметра --stepwise-skip можно пропустить один неудачный тест и остановить выполнение на втором. Это полезно, если вы застряли на неудачном тесте и хотите пока пропустить его. Указание --stepwise-skip также неявно включает --stepwise.

© 2015–2026 Holger Krekel and pytest-dev team
Licensed under the MIT License.
https://docs.pytest.org/en/stable/how-to/cache.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API