Ответ
В контексте тестирования на Python декораторы широко используются в фреймворках (pytest, unittest) для пометки тестов, настройки фикстур, параметризации и управления их выполнением. Объявление кастомного декоратора для тестов следует общему синтаксису Python.
1. Базовое объявление декоратора для логирования или измерения времени выполнения теста:
import time
import functools
def log_execution_time(func):
"""Декоратор для логирования времени выполнения теста."""
@functools.wraps(func) # Сохраняем метаданные оригинальной функции
def wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs) # Выполняем сам тест
end_time = time.perf_counter()
print(f"Тест {func.__name__} выполнен за {end_time - start_time:.4f} сек")
return result
return wrapper
# Применение к тестовой функции
@log_execution_time
def test_calculation_performance():
# ... код теста ...
assert heavy_calculation() == expected_result
2. Декоратор для повторения падающего теста (retry logic):
def retry_on_failure(max_attempts=3):
"""Декоратор для повторного запуска теста при неудаче."""
def decorator(test_func):
@functools.wraps(test_func)
def wrapper(*args, **kwargs):
for attempt in range(1, max_attempts + 1):
try:
return test_func(*args, **kwargs)
except AssertionError as e:
if attempt == max_attempts:
raise # Пробрасываем ошибку после последней попытки
print(f"Попытка {attempt} не удалась, повторяем... ({e})")
return None
return wrapper
return decorator
@retry_on_failure(max_attempts=2)
def test_flaky_integration():
# Этот тест иногда падает из-за внешней зависимости
response = call_unstable_api()
assert response.status_code == 200
3. Использование встроенных декораторов фреймворков (pytest):
import pytest
@pytest.mark.slow # Помечаем тест как медленный
@pytest.mark.parametrize("input,expected", [("1+2", 3), ("2*3", 6)]) # Параметризация
@log_execution_time # Можно комбинировать декораторы
def test_parametrized_calculation(input, expected):
assert eval(input) == expected
Зачем это QA-инженеру: Кастомные декораторы помогают добавлять сквозную функциональность (логирование, retry, setup/teardown) к множеству тестов без дублирования кода, делая тестовый набор более управляемым и информативным.