pytest fixtures, параметризация тестов, настройка окружения через конфигурацию
Фикстуры pytest — это механизм подготовки окружения для тестов. Они создают браузер, авторизуют пользователя, подготавливают данные — и автоматически очищают всё после теста.
После установки pytest-playwright вам доступны три встроенные фикстуры:
def test_homepage(page):
page.goto('/')
assert page.title() == 'Главная'| Фикстура | Что создаёт | Время жизни |
|---|---|---|
browser | Процесс браузера (Chromium/Firefox/WebKit) | Сессия (один на все тесты) |
context | BrowserContext (изолированная сессия) | Функция (новый для каждого теста) |
page | Page (вкладка внутри контекста) | Функция (новая для каждого теста) |
browser создаётся один раз на весь прогон — это экономит время. context и page создаются для каждого теста — это обеспечивает изоляцию.
Переопределите фикстуру context в conftest.py, чтобы задать viewport, locale и другие параметры:
# conftest.py
import pytest
@pytest.fixture
def context(context):
return context.new_context(
viewport={'width': 1920, 'height': 1080},
locale='ru-RU',
timezone_id='Europe/Moscow',
)Теперь каждый тест получит страницу с нужными настройками:
def test_russian_locale(page):
page.goto('/settings')
# Страница отображает даты в формате ДД.ММ.ГГГГ
assert '01.01.2026' in page.content()Важно: при переопределении фикстуры нужно вернуть новый контекст. Встроенный
contextуже создан плагином — вызовитеcontext.new_context()с нужными параметрами.
Самая частая кастомная фикстура — авторизованный пользователь:
# conftest.py
import pytest
@pytest.fixture
def logged_in_page(page):
page.goto('/login')
page.get_by_label('Email').fill('user@example.com')
page.get_by_label('Пароль').fill('secret123')
page.get_by_role('button', name='Войти').click()
# Ждём перехода на dashboard
page.wait_for_url('**/dashboard')
yield pageИспользование в тестах:
def test_dashboard_content(logged_in_page):
# Пользователь уже авторизован
assert page.get_by_role('heading', name='Добро пожаловать').is_visible()Если логин медленный (например, через SSO), выполните его один раз и сохраните сессию:
# conftest.py
import pytest
from pathlib import Path
AUTH_FILE = Path('auth/admin.json')
@pytest.fixture(scope='session')
def admin_context(browser):
context = browser.new_context()
page = context.new_page()
# Логин
page.goto('/login')
page.get_by_label('Email').fill('admin@example.com')
page.get_by_label('Пароль').fill('admin_secret')
page.get_by_role('button', name='Войти').click()
page.wait_for_url('**/admin')
# Сохраняем сессию
context.storage_state(path=AUTH_FILE)
context.close()
yield
@pytest.fixture
def admin_page(page):
# Переиспользуем авторизованную сессию
page.context.storage_state(path=AUTH_FILE)
yield pageКаждый тест получает страницу с уже авторизованным admin — без повторного логина.
@pytest.mark.parametrize запускает один тест с разными входными данными:
import pytest
@pytest.mark.parametrize('url,expected_status', [
('/', 200),
('/about', 200),
('/missing', 404),
('/api/health', 200),
])
def test_pages_status(page, url, expected_status):
response = page.goto(url)
assert response.status == expected_statuspytest запустит этот тест 4 раза — каждый раз с новыми url и expected_status. В отчёте каждый набор виден как отдельный тест.
Параметризация с локаторами:
@pytest.mark.parametrize('role,expected_text', [
('admin', 'Панель администратора'),
('manager', 'Управление проектами'),
('viewer', 'Только просмотр'),
])
def test_role_based_content(logged_in_page, role, expected_text):
logged_in_page.goto('/dashboard')
assert expected_text in logged_in_page.content()Можно комбинировать параметризацию с кастомными фикстурами:
@pytest.fixture
def user_page(page, request):
"""Фикстура, которая логинится с разными ролями."""
role = request.param # значение из @pytest.mark.parametrize
page.goto('/login')
page.get_by_label('Email').fill(f'{role}@example.com')
page.get_by_label('Пароль').fill('password')
page.get_by_role('button', name='Войти').click()
page.wait_for_url('**/dashboard')
yield page
@pytest.mark.parametrize('user_page', ['admin', 'manager', 'viewer'], indirect=True)
def test_dashboard_for_roles(user_page):
assert user_page.get_by_role('heading').is_visible()indirect=True передаёт значение параметра в фикстуру через request.param.
Настройте общие параметры в pytest.ini:
[pytest]
addopts =
--browser chromium
--base-url=https://staging.example.com
--tracing=on
--headed
testpaths = tests/Теперь pytest запустит тесты с этими флагами по умолчанию.
Используйте yield для очистки после теста:
@pytest.fixture
def page_with_cleanup(page):
yield page
# Этот код выполнится после теста
page.evaluate('localStorage.clear()')
page.evaluate('sessionStorage.clear()')Или создайте данные перед тестом и удалите после:
@pytest.fixture
def test_user(page):
# Создаём пользователя
page.goto('/admin/users/new')
page.get_by_label('Email').fill('testuser@example.com')
page.get_by_role('button', name='Создать').click()
page.wait_for_selector('.user-created')
yield 'testuser@example.com'
# Удаляем пользователя после теста
page.goto('/admin/users')
page.get_by_text('testuser@example.com').click()
page.get_by_role('button', name='Удалить').click()| Scope | Когда создаётся | Когда уничтожается |
|---|---|---|
function (по умолчанию) | Перед каждым тестом | После каждого теста |
class | Перед первым тестом класса | После последнего теста класса |
module | Перед первым тестом модуля | После последнего теста модуля |
session | Один раз при запуске pytest | При завершении pytest |
Для e2e-тестов function — самый безопасный выбор. session используйте только для чтения (например, storage_state).
❌ Использование scope='session' для тестов, изменяющих данные. Все тесты используют один контекст — изменения одного теста влияют на другие.
❌ Глобальные переменные вместо фикстур. auth_token = None на уровне модуля — это антипаттерн. Фикстуры дают явные зависимости и автоматическую очистку.
❌ Переопределение browser без закрытия. Если вы создаёте свой браузер в фикстуре — не забудьте yield + browser.close().
✅ Правильный подход: function-фикстуры для изоляции, session для авторизации через storage_state, параметризация для покрытия множества сценариев.
conftest.py с фикстурой logged_in_page, которая выполняет логин и переходит на /dashboard.storage_state в файл, и переиспользует его в других тестах.Изучите mocking и перехват запросов, чтобы научиться подменять API-ответы и тестировать UI независимо от бэкенда.
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.