Сообщить об ошибке.

Пользовательские pytest.mark с аргументами модуля pytest в Python

Содержание:


Пользовательские метки с параметрами.

Фреймворк pytest создает пользовательские метки с аргументами динамически с использованием фабричного объекта pytest.mark. Затем созданные метки применяются к функциям в качестве декоратора. Аргументы пользовательских меток читаются фикстурой тестовой функции и могут передаваться в саму тестовую функцию.

Например:

@pytest.mark.timeout(10, "slow", method="thread")
def test_function():
    ...

Этот код создаст и прикрепит объект Mark к собранному элементу, к которому затем можно будет получить доступ с помощью объекта фикстуры request через хук pytest.node.iter_markers(). Объект метки mark будет иметь следующие атрибуты:

mark.name == "timeout"
mark.args == (10, "slow")
mark.kwargs == {"method": "thread"}

Пример использования нескольких пользовательских меток:

@pytest.mark.timeout(10, "slow", method="thread")
@pytest.mark.slow
def test_function():
    ...

Полный пример извлечения аргументов из пользовательских меток.

Когда итератор request.node.iter_markers или for ... in request.node.iter_markers_with_node(name=None) используются с несколькими декораторами пользовательских меток, то маркер, ближайший к функции, будет итерироваться первым. Приведенный выше пример приведет к @pytest.mark.slow, за которым следует @pytest.mark.timeout(...).

Регистрация пользовательских меток.

Чтобы зарегистрировать пользовательскую метку, необходимо ее название просто добавить в файл pytest.ini, который расположен в корне проекта:

# pytest.ini
[pytest]
markers =
    fixt_data(arg1, arg2): маркер с аргументами.
    slow: медленный тест.

Внимание! Не используйте в названиях маркеров ключевые слова языка Python.

Незарегистрированные метки всегда будут выдавать предупреждение warning. Можно отключить предупреждение для пользовательских меток, зарегистрировав их программно, используя хук pytest_configure().

def pytest_configure(config):
    # регистрируется метка с параметрами `@pytest.mark.fixt_data(data)`
    config.addinivalue_line("markers", "fixt_data(data): регистрация маркера с параметрами")
    # регистрируется метка `@pytest.mark.slow`
    config.addinivalue_line("markers", "slow: медленный тест.")

Примеры доступа к аргументам пользовательской метки.

Используя объект запроса request, фикстура также может получить доступ к пользовательским маркерам, которые применяются к тестовой функции. Такое поведение может быть полезно для передачи данных в фикстуру из теста или в тест через фикстуру:

import pytest

@pytest.fixture
def fixt(request):
    # Считываем данные, по имени маркера
    # примененного к тесту `test_fixt()`
    marker = request.node.get_closest_marker("fixt_data")
    if marker is None:
        # Каким-то образом обработать отсутствующий маркер...
        data = None
    else:
        data = marker.args[0]

    # Делаем что-то с данными и возвращаем
    return data

# Маркер передает данные тестовой функции
@pytest.mark.fixt_data(42)
# функция принимает фикстуру `fixt`
def test_fixt(fixt):
    assert fixt == 42

Другой пример: Маркеры можно взять из атрибута узла запроса фикстуры с помощью request.node.iter_markers():

import pytest

@pytest.fixture
def get_marks(request):
    # фикстура получает доступ к маркерам теста 
    # `test_marks()` при помощи аргумента `request`
    marks = [m.name for m in request.node.iter_markers()]
    if request.node.parent:
        marks += [m.name for m in request.node.parent.iter_markers()]
    yield marks

@pytest.mark.parametrize('number', [1, 2, 3])
@pytest.mark.foo
@pytest.mark.xfail
def test_marks(get_marks, number):
    print(get_marks)
    assert 'xfail' in get_marks
    assert number == 42