params
);pytest.param()
.pytest
.В фикстуры можно передавать параметры для неоднократно выполнения тестов, использующих эти фикстуры. Обычно повторно запускаемые тестовые функции не зависят друг от друга. И в этом случае параметризация фикстур помогает писать исчерпывающие функциональные тесты для компонентов, которые сами по себе могут быть сконфигурированы разными способами.
import pytest import smtplib # аргумент `params` отвечает за передачу нескольких параметров @pytest.fixture(params=["smtp.gmail.com", "mail.python.org"]) def smtp_connection(request): # request.param читает параметры по одному за раз connect = smtplib.SMTP(request.param, 587, timeout=5) print(f"Соединение с {request.param} открыто") yield connect connect.close() print(f"Соединение с {request.param} закрыто") def test_ehlo(smtp_connection): print("Тест начался") response, msg = smtp_connection.ehlo() assert response == 250 print("Тест завершился")
Аргумент params
в декораторе @pytest.fixture()
принимает список параметров, для каждого из которых фикстура будет выполняться и получать значение через request.param
.
Если запустить код командой $ pytest -v -s test.py
, то будет виден весь вывод функции print()
, и то, что тестовая функция была выполнена дважды, сначала с одним, потом с другим объектом connect
.
Для каждого значения параметра фикстуры pytest
сгенерирует ID-строку, которая его идентифицирует. Можно использовать эти ID для запуска отдельного варианта теста (смотрите Как запускать тесты с модулем pytest
) . Если запустить $ pytest --collect-only test.py
, то можно увидеть все сгенерированные ID-строки.
<Module test.py> <Function test_ehlo[smtp.gmail.com]> <Function test_ehlo[mail.python.org]>
Используя объект запроса request
, фикстура также может получить доступ к пользовательским маркерам, которые применяются к тестовой функции. Такое поведение может быть полезно для передачи данных в фикстуру из теста:
import pytest @pytest.fixture def fixt(request): # Считываем данные маркета с данными, примененного к тесту 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
Для маркировки значений параметров параметризованных фикстур можно использовать функцию pytest.param()
точно так же, как и с @pytest.mark.parametrize
.
Пример:
import pytest @pytest.fixture(params=[0, 1, pytest.param(2, marks=pytest.mark.skip)]) def data_set(request): return request.param def test_data(data_set): pass
При выполнении этого теста вызов data_set()
со значением 2 будет пропущен (skipped).
pytest.param(*values, id, marks)
.Функция pytest.param()
позволяет указать наряду с передаваемыми значениями *values
дополнительные параметры (id
, marks
) в вызовах @pytest.mark.parametrize
или при передачи параметров (params) в фикстуру pytest
.
Принимаемые аргументы:
values
: кортеж значений передаваемых параметров.marks
: необязательная отдельная метка или список меток, которые будут применены к этим параметрам.id
: необязательная строка, представляющая идентификатор, который нужно присвоить этим параметрам (применяется для выборочного запуска при тестировании).Пример:
@pytest.mark.parametrize( "test_input,expected", [("3+5", 8), pytest.param("6*9", 42, marks=pytest.mark.xfail),], ) def test_eval(test_input, expected): assert eval(test_input) == expected