Pytest Patterns: Элегантный Teardown через yield и оптимизация скоупов Если вы все еще пишете def teardown_method(self): в классах тестов, вы не испол…
Если вы все еще пишете def teardown_method(self): в классах тестов, вы не используете мощь Pytest на 100%.
Фикстуры (fixtures) - это не просто способ передать данные. Это полноценный механизм управления жизненным циклом зависимостей (DI).
1. yield вместо return: Встроенный Teardown
В Pytest фикстура может "замереть", отдать управление тесту, а потом продолжить выполнение. Это реализуется через генератор yield.
Код до yield - это setUp.
Код после yield - это tearDown.
Пример (временная база данных):
import pytest
from sqlalchemy import create_engine
@pytest.fixture
def db_engine():
# Setup: Поднимаем соединение
engine = create_engine("sqlite:///:memory:")
# Передаем объект в тест
yield engine
# Teardown: Этот код выполнится ПОСЛЕ завершения теста
# (даже если тест упал с ошибкой!)
engine.dispose()
Это гарантирует, что ресурсы будут освобождены, и вам не нужны try/finally блоки внутри самих тестов.
2. Scopes: Не создавайте мир заново
По умолчанию фикстура имеет scope='function'. Она создается и умирает для каждого теста. Это безопасно, но медленно, если мы говорим о поднятии Docker-контейнера или коннекта к БД.
Используйте scope='session' для тяжелых ресурсов, которые можно переиспользовать.
Паттерн "Изоляция при общем ресурсе":
Частая задача Middle+: иметь одну БД на весь прогон тестов (быстро), но чистые таблицы для каждого теста (изолированно).
Решение: комбинируем скоупы.
# Живет весь прогон тестов (создается 1 раз)
@pytest.fixture(scope="session")
def db_engine():
engine = create_engine(...)
yield engine
engine.dispose()
# Живет 1 тест (создается N раз)
@pytest.fixture(scope="function")
def db_session(db_engine):
# Берем engine из сессионной фикстуры
connection = db_engine.connect()
transaction = connection.begin() # Начали транзакцию
session = Session(bind=connection)
yield session
session.close()
# ROLLBACK транзакции после теста вернет базу в исходное состояние!
transaction.rollback()
connection.close()
Итог:
🟢 Используйте yield для очистки ресурсов.
🟢 Тяжелые объекты (Engine, Client, Container) - в scope='session'.
🟢 Легкие объекты с состоянием (Session, User) - в scope='function', наследуясь от тяжелых.
#pytest #testing #qa #bestpractices #python
👉 @BookPython