Как отключить пропуск теста в pytest без изменения кода? - PullRequest
3 голосов
/ 10 мая 2019

Я унаследовал некоторый код, который реализует pytest.mark.skipif для нескольких тестов. Читая документы pytest, я осознаю, что могу добавлять условия, возможно проверять переменные среды или использовать более продвинутые функции pytest.mark для совместного управления группами тестов. К сожалению, пока ничего в документации не решает мою проблему.

Я хочу просто отключить пропуски тестов, но без изменения исходного кода тестов. Я просто хочу запустить pytest в режиме, где он не учитывает никаких индикаторов пропуска тестов. Существует ли такое решение с pytest?

Ответы [ 3 ]

1 голос
/ 10 мая 2019

Обходной путь, позволяющий игнорировать пропущенные метки, заключается в их программном удалении. Создайте conftest.py со следующим содержимым:

def pytest_collection_modifyitems(items):
    for item in items:
        for node in reversed(item.listchain()):
            node.own_markers = [m for m in node.own_markers if m.name not in ('skip', 'skipif')]

Однако, это портит pytest внутренности и может легко сломаться при pytest обновлениях; правильный способ игнорирования пропусков должен определять ваш собственный механизм пропуска, например:

@pytest.hookimpl(tryfirst=True)
def pytest_runtest_setup(item):
    mark = item.get_closest_marker(name='myskip')
    if mark:
        condition = next(iter(mark.args), True)
        reason = mark.kwargs.get('reason', 'custom skipping mechanism')
        item.add_marker(pytest.mark.skipif(not os.getenv('PYTEST_RUN_FORCE_SKIPS', False) and condition, reason=reason), append=False)

Аннотируйте тесты с помощью @pytest.mark.myskip вместо @pytest.mark.skip и @pytest.mark.myskip(condition, reason) вместо @pytest.mark.skipif(condition, reason):

@pytest.mark.myskip
def test_skip():
    assert True


@pytest.mark.myskip(1 == 1, reason='my skip')
def test_skipif():
    assert True

При регулярном запуске myskip будет вести себя так же, как и pytest.mark.skip / pytest.mark.skipif. Настройка PYTEST_RUN_FORCE_SKIPS отключит его:

$ PYTEST_RUN_FORCE_SKIPS=1 pytest -v
...
test_spam.py::test_skip PASSED
test_spam.py::test_skipif PASSED
...

Конечно, вы не должны больше использовать pytest.mark.skip / pytest.mark.skipif, поскольку они не будут зависеть от PYTEST_RUN_FORCE_SKIPS env var.

1 голос
/ 12 мая 2019

Простой обходной путь - установить обезьяну pytest.mark.skipif в вашем conftest.py:

import pytest

old_skipif = pytest.mark.skipif

def custom_skipif(*args, **kwargs):
    return old_skipif(False, reason='disabling skipif')

pytest.mark.skipif = custom_skipif
1 голос
/ 10 мая 2019

Хорошо, реализация не допускает этого с нулевыми модификациями.Вам понадобится пользовательский маркер.Добавьте следующее к conftest.py, затем измените все отметки skipif на custom_skipif.Используйте pytest --no-skips.

import pytest
from _pytest.mark.evaluate import MarkEvaluator

def pytest_addoption(parser):
    parser.addoption(
        "--no-skips", action="store_true", default=False, help="disable custom_skip marks"
    )

@hookimpl(tryfirst=True)
def pytest_runtest_setup(item):
    if item.config.getoption('--no-skips'):
        return

    # Check if skip or skipif are specified as pytest marks
    item._skipped_by_mark = False
    eval_skipif = MarkEvaluator(item, "custom_skipif")
    if eval_skipif.istrue():
        item._skipped_by_mark = True
        pytest.skip(eval_skipif.getexplanation())

    for skip_info in item.iter_markers(name="custom_skip"):
        item._skipped_by_mark = True
        if "reason" in skip_info.kwargs:
            pytest.skip(skip_info.kwargs["reason"])
        elif skip_info.args:
            pytest.skip(skip_info.args[0])
        else:
            pytest.skip("unconditional skip")

    item._evalxfail = MarkEvaluator(item, "xfail")
    check_xfail_no_run(item)

Реализация копируется и модифицируется из самого pytest в skipping.py.

...