Как сделать, чтобы фикстура была вызвана после завершения?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Управление вызовом фикстур после завершения теста
В Pytest для управления временем вызова фикстур используются scope и механизм finalizer/yield. Чтобы фикстура выполняла какие-либо действия ПОСЛЕ завершения теста или сессии, существует несколько основных подходов.
1. Фикстура с использованием yield (контекстный менеджер)
Это наиболее распространённый и рекомендуемый способ. Код после yield выполняется после завершения теста (или в зависимости от scope).
import pytest
@pytest.fixture(scope="function")
def resource_setup_teardown():
# Действия ДО теста
print("\nНастройка ресурсов перед тестом")
resource = {"data": "test_data", "active": True}
yield resource # Передаём ресурс в тест
# Действия ПОСЛЕ теста
print("Очистка ресурсов после теста")
resource["active"] = False
del resource["data"]
Важные особенности:
- Код после
yieldвыполняется независимо от результата теста (pass/fail) - Можно использовать различные
scope:function,class,module,session - Если возникает исключение до
yield, код послеyieldне выполняется
2. Использование addfinalizer для более сложных сценариев
Этот подход полезен, когда нужно зарегистрировать несколько финализаторов или когда логика финализатора определяется динамически.
import pytest
@pytest.fixture(scope="module")
def database_connection(request):
# Инициализация соединения
conn = {"status": "connected", "session_id": 12345}
print(f"Создано соединение: {conn['session_id']}")
def close_connection():
# Этот код выполнится после завершения
print(f"Закрытие соединения: {conn['session_id']}")
conn["status"] = "disconnected"
# Здесь может быть реальное закрытие БД, файла и т.д.
# Регистрируем финализатор
request.addfinalizer(close_connection)
return conn
Преимущества addfinalizer:
- Можно добавить несколько финализаторов
- Финализаторы выполняются в обратном порядке добавления
- Работает даже если исключение происходит до возврата фикстуры
3. Фикстура с scope="session" для глобальной очистки
Для действий, которые должны выполниться один раз после ВСЕХ тестов:
import pytest
import tempfile
import os
@pytest.fixture(scope="session", autouse=True)
def global_cleanup(request):
# Создаём временную директорию для всей сессии
temp_dir = tempfile.mkdtemp()
print(f"Создана временная директория: {temp_dir}")
def remove_temp_dir():
# Выполнится после ВСЕХ тестов
print(f"Удаление временной директории: {temp_dir}")
import shutil
if os.path.exists(temp_dir):
shutil.rmtree(temp_dir)
request.addfinalizer(remove_temp_dir)
return temp_dir
4. Автоматическое использование фикстур (autouse=True)
Чтобы фикстура выполнялась автоматически без явного указания в параметрах теста:
import pytest
@pytest.fixture(scope="function", autouse=True)
def log_test_duration(request):
import time
start_time = time.time()
yield
duration = time.time() - start_time
print(f"Тест {request.node.name} выполнен за {duration:.2f} секунд")
# Здесь можно логировать в файл, отправлять в мониторинг и т.д.
5. Комбинированный пример с обработкой исключений
import pytest
@pytest.fixture(scope="function")
def file_processor(request):
files_to_cleanup = []
def create_test_file(filename):
with open(filename, 'w') as f:
f.write("test content")
files_to_cleanup.append(filename)
return filename
def cleanup_files():
import os
print(f"Очистка {len(files_to_cleanup)} файлов")
for file in files_to_cleanup:
try:
if os.path.exists(file):
os.remove(file)
print(f"Удалён файл: {file}")
except Exception as e:
print(f"Ошибка при удалении {file}: {e}")
request.addfinalizer(cleanup_files)
return create_test_file
# Использование в тесте
def test_file_operations(file_processor):
file1 = file_processor("test1.txt")
file2 = file_processor("test2.txt")
# Оба файла будут удалены ПОСЛЕ теста
Ключевые моменты для выбора подхода:
yield— идеален для простых сценариев setup/teardownaddfinalizer— выбирайте когда нужно:- Несколько независимых финализаторов
- Динамическое создание ресурсов
- Гарантированное выполнение даже при ошибках в setup
scopeопределяет когда выполнится финализатор:function— после каждого тестаclass— после всех тестов классаmodule— после всех тестов модуляsession— после всей сессии тестов
autouse=True— когда фикстура должна применяться ко всем тестам автоматически
Правильное использование этих механизмов позволяет создавать надёжные тесты с гарантированным освобождением ресурсов, что особенно критично при работе с базами данных, сетевыми соединениями, файловой системой или внешними API.