Фикстуры
Что такое фикстура?
подробнее
Фикстуры в pytest — это вспомогательные функции для подготовки среды и очистки ресурсов. Декоратор
@pytest.fixtureпомечает функцию как ресурс. Тест получает результат фикстуры, принимая её имя как аргумент.
Пример простейшей фикстуры
@pytest.fixture
def my_fixture():
return "hello world"
def test_helloworld(my_fixture):
print(my_fixture) # hello world
Какие есть встроенные фикстуры?
подробнее
-
tmp_path: Создание временной директории. Возвращает объект
pathlib.Path. Директория уникальна для каждого теста и автоматически удаляется через несколько запусков.
Пример:f = tmp_path / "test.txt" f.write_text("hello") - monkeypatch: Подмена (mock) атрибутов, словарей,
os.environ. Незаменима, когда нужно временно “сломать” или заменить поведение функции, чтобы не ходить в реальную сеть или БД.
Пример:monkeypatch.setenv("DATABASE_URL", "mock_url") - capsys: Перехват вывода в консоль (
stdout,stderr). Например можно перехватитьprint(...)и проверить что выведется то, что нужно.
Пример:out, err = capsys.readouterr() - request: “Магическая” фикстура, которая дает доступ к контексту выполнения теста. Часто используется внутри других фикстур для получения параметров.
Пример:request.node.nameилиrequest.param - pytestconfig: Доступ к конфигам (
pytest.ini) и флагам CLI (-v,-s,--lf, …).
Пример:pytestconfig.getoption("verbose")
Какие параметры принимает декоратор @pytest.fixture?
подробнее
- scope — область действия (жизненный цикл) фикстуры. (
function,class,module,package,session) - params — список значений для параметризации фикстуры. Тест запустится столько раз, сколько элементов в списке. Доступ к значениям внутри фикстуры — через
request.param. - autouse (
bool) — еслиTrue, фикстура применится ко всем тестам в её области видимости автоматически, даже если её не указывать в аргументах теста. - ids — список строк или функция для формирования красивых названий тестов при параметризации.
- name — позволяет задать фикстуре псевдоним. В тесте тогда нужно использовать это имя, а не имя самой функции.
Пример
@pytest.fixture(scope="session", autouse=True, params=[1, 2], ids=["one", "two"], name="my_db")
def db_fixture(request):
return request.param
def test_db(my_db):
...
Какие бывают области видимости (scope) у фикстур?
подробнее
Параметр
scopeможно понимать как область видимости, область действия, жизненный цикл или уровень. Он определяет «живучесть» фикстуры (как часто она пересоздаётся).
- function (по умолчанию) — создаётся для каждого теста (каждой функции).
- class — один раз на класс тестов.
- module — один раз на модуль.
- package — один раз на пакет.
- session — один раз на весь прогон тестов.
Параметризация фикстур
подробнее
Параметризация фикстур позволяет запустить один и тот же набор тестов несколько раз с разными входными данными. Это «умножает» количество тестов без дублирования кода.
Параметризация фикстуры удобна, если одни и те же данные (например, разные БД или браузеры) нужны множеству разных тестов в отличии от@pytest.mark.parametrize, когда когда данные нужны только этому тесту.
Для параметризации используются:
params: Список значений.request: Специальная фикстура, через которую мы получаем текущее значение из params.ids: Список имен для каждого прогона (чтобы в консоли тесты назывались понятно).
Пример
@pytest.fixture(params=["chrome", "firefox", "safari"], ids=["CH", "FF", "SF"])
def browser(request):
driver = setup_browser(request.param) # request.param — текущее значение
yield driver
driver.quit()
def test_login(browser):
browser.get("https://site.com")
# Этот тест выполнится 3 раза (для каждого браузера)
Можно ли передать фикстуру в фикстуру?
подробнее
Фикстура может принимать другие фикстуры как аргументы.
Pytest сначала выполнит «вложенную» фикстуру, а затем ту, которая её вызывает.
Области видимости (Scopes): Важно помнить правило: фикстура с широкимscope(например,session) не может зависеть от фикстуры с узкимscope(например,function). Наоборот — можно.
Пример
@pytest.fixture
def user_data():
return {"name": "Alice", "role": "admin"}
@pytest.fixture
def user_token(user_data): # Передаем фикстуру в фикстуру
return f"token_{user_data['name']}"
def test_api(user_token):
assert "Alice" in user_token
Преимущества
- Атомарность: Каждая фикстура делает что-то одно (одна создает юзера, другая — авторизует).
- Переиспользование: Не нужно в каждой фикстуре заново писать код создания пользователя.
yield в фикстуре
подробнее
returnзавершает выполнение функции. Код после него не выполнится.
yield“ставит функцию на паузу”, пока идет тест, а потом возвращается, чтобы доделать очистку.
Ключевое слово
yieldразделяет работу фикстуры на два этапа:
- Setup (Подготовка): Весь код до
yield. Выполняется перед тестом.- Teardown (Очистка): Весь код под
yield. Выполняется сразу после завершения теста (даже если тест упал с ошибкой).То, что стоит после
yield, передается в тест как аргумент.
Пример
@pytest.fixture
def db():
# --- Setup ---
connection = connect_db()
yield connection # Передаем ресурс тесту
# --- Teardown ---
connection.close()
Параметр autouse
подробнее
Чтобы фикстура запускалась автоматически для всех тестов в её области видимости (без передачи её в аргументы), используется параметр
autouse=True.
Зачем: Для фоновых действий: логирование, замер времени, очистка БД перед каждым тестом, создание папок.
Опасность: Чрезмерное использование делает тесты “магическими” и менее понятными.
Пример
@pytest.fixture(autouse=True)
def clean_logs():
clear_log_file() # Будет запускаться перед КАЖДЫМ тестом