Фикстура в pytest — это функция, которая позволяет настроить необходимое состояние теста. Фикстуры могут предоставлять данные, конфигурацию или другие компоненты, чтобы обеспечивать повторное использование кода и упрощать написание тестов.
Пример простой фикстуры:
import pytest
@pytest.fixture
def sample_data():
data = {"key": "value"}
return data
def test_sample(sample_data):
assert sample_data["key"] == "value"
В приведенном примере sample_data
— это фикстура. Она передается в функцию теста test_sample()
как аргумент.
pytest предоставляет ряд встроенных фикстур, которые существенно упрощают написание тестов. Ниже рассмотрены некоторые из наиболее популярных и полезных встроенных фикстур:
tmp_path
— предоставляет объект пути (из стандартной библиотеки pathlib) к временному каталогу, который уникален для каждой функции теста.def test_write_file(tmp_path):
data_file = tmp_path / "data.txt"
data_file.write_text("Hello, pytest!")
assert data_file.read_text() == "Hello, pytest!"
tmpdir
— похож на tmp_path
, но предоставляет объекты из библиотеки py.path.def test_create_directory(tmpdir):
dir = tmpdir.mkdir("example")
assert dir.isdir()
capsys
— позволяет перехватывать вывод в stdout
и stderr
.def test_output(capsys):
print("Hello, pytest!")
captured = capsys.readouterr()
assert captured.out == "Hello, pytest!\n"
monkeypatch
— предоставляет удобные методы для безопасного изменения и восстановления объектов, атрибутов, словарей, переменных окружения и т.д.def test_environment_variable(monkeypatch):
monkeypatch.setenv("MY_VAR", "value")
assert os.environ["MY_VAR"] == "value"
pytestconfig
— дает доступ к конфигурации pytest, например, к аргументам командной строки или значениям из pytest.ini.def test_pytestconfig(pytestconfig):
assert pytestconfig.option.verbose > 0
recwarn
— Перехватывает предупреждения во время выполнения тестов.import warnings
def test_warning(recwarn):
warnings.warn("This is a warning!")
assert len(recwarn) == 1
assert str(recwarn[0].message) == "This is a warning!"
request
— дает информацию о текущем тесте или фикстуре, например, параметры, маркеры и др.@pytest.mark.my_marker
def test_request_object(request):
assert request.node.get_closest_marker(name="my_marker") is not None
Это лишь некоторые из встроенных фикстур в pytest. У них есть множество применений, и они часто используются для упрощения процесса написания тестов.
conftest.py — это специальный файл в pytest, который используется для предоставления фикстур, плагинов или другой конфигурации, которые доступны для нескольких тестовых модулей.
Например, если у вас есть фикстура, которую вы хотите использовать в нескольких тестовых файлах, вы можете определить ее в conftest.py, и она будет автоматически доступна для всех тестов.
Пример conftest.py:
import pytest
@pytest.fixture
def common_data():
data = {"common_key": "common_value"}
return data
Теперь фикстура common_data
доступна для всех тестов, находящихся в той же папке, что и conftest.py, и во всех вложенных папках.
Одной из мощных особенностей pytest является возможность параметризации фикстур. Это позволяет создавать динамические тестовые сценарии на основе набора данных, который предоставляется фикстурой.
Пример:
import pytest
# Определение параметризованной фикстуры
@pytest.fixture(params=[1, 2, 3])
def number_fixture(request):
return request.param
def test_numbers(number_fixture):
assert number_fixture in [1, 2, 3]
Здесь у нас есть фикстура number_fixture
, которая возвращает три разных значения (1, 2 или 3). Это приведет к тому, что тест test_numbers
будет автоматически выполнен три раза с каждым из этих значений.
Фикстуры в pytest могут использовать yield
для того, чтобы выполнять код после завершения теста. Это особенно полезно для задач очистки, например, закрытия соединения с базой данных.
Пример:
import pytest
@pytest.fixture
def database_connection():
conn = connect_to_db()
yield conn # Это значение передается тесту
conn.close() # Этот код будет выполнен после завершения теста
Фикстуры могут зависеть от других фикстур, что позволяет создавать сложные сценарии настройки.
Пример:
@pytest.fixture
def database():
return Database()
@pytest.fixture
def table(database):
table = database.create_table("example")
yield table
database.drop_table("example")
В примере выше фикстура table
зависит от фикстуры database
. Когда тест запрашивает table
, сначала вызывается database
, затем table
.
Фикстура с аргументом autouse=True
будет автоматически применяться ко всем тестам в модуле. Вы можете использовать это, чтобы выполнять настройку или очистку для каждого теста без явного указания фикстуры в аргументах теста.
Пример:
import pytest
@pytest.fixture(autouse=True)
def setup_and_teardown():
# Настройка перед каждым тестом
print("Setup!")
yield
# Очистка после каждого теста
print("Teardown!")
def test_example_1():
assert True
def test_example_2():
assert 2 + 2 == 4
Объект request
внутри фикстуры позволяет получить информацию о текущем "использующем" тесте. Это может быть полезно, например, для динамического изменения поведения фикстуры на основе атрибутов теста.
Пример:
@pytest.fixture
def example_data(request):
marker = request.node.get_closest_marker("data_type")
if marker:
data_type = marker.args[0]
if data_type == "type1":
return {"key": "value1"}
elif data_type == "type2":
return {"key": "value2"}
return {}
@pytest.mark.data_type("type1")
def test_data_type_1(example_data):
assert example_data["key"] == "value1"
@pytest.mark.data_type("type2")
def test_data_type_2(example_data):
assert example_data["key"] == "value2"
Иногда вам может понадобиться явно добавить функцию завершения к вашей фикстуре. Это можно сделать с помощью request.addfinalizer
.
@pytest.fixture
def setup_example(request):
resource = allocate_resource()
def fin():
resource.release()
request.addfinalizer(fin)
return resource
Помимо параметризации тестов, вы также можете параметризовать фикстуры. С помощью аргумента params вы можете определить набор значений, которые фикстура должна передать тесту.
@pytest.fixture(params=[0, 1, 2])
def number(request):
return request.param
def test_number(number):
assert number in [0, 1, 2]
Фикстуры в pytest представляют собой одну из наиболее мощных и гибких возможностей фреймворка. Они не только обеспечивают структурированный и удобный механизм для настройки и очистки ресурсов, но и позволяют делать это на различных уровнях области видимости: от отдельных тестовых функций до всей тестовой сессии.
Использование фикстур помогает:
Кроме того, благодаря широкому спектру встроенных фикстур, а также возможности кастомизации и расширения, pytest предоставляет тестировщикам все необходимые инструменты для эффективного и качественного тестирования программного обеспечения в различных условиях.
Фикстуры — это центральная часть экосистемы pytest, и умение их эффективно использовать станет важным навыком для любого, кто хочет достичь мастерства в автоматическом тестировании с использованием этого инструмента.
Содержание: