Ответ
Да, писал. Стандартных декораторов Pytest часто недостаточно для сложной логики управления тестами. Я создавал собственные декораторы для решения специфичных задач проекта.
Пример 1: Декоратор для повторного запуска упавших тестов только в определенном окружении.
import pytest
import os
def retry_on_staging(f):
"""Декоратор, который повторяет падающий тест 2 раза, но только если переменная окружения ENV=staging."""
def wrapper(*args, **kwargs):
max_retries = 2 if os.getenv('ENV') == 'staging' else 0
for attempt in range(max_retries + 1):
try:
return f(*args, **kwargs)
except AssertionError as e:
if attempt == max_retries:
raise e
print(f"Retry {attempt + 1} for {f.__name__} due to {e}")
return wrapper
@retry_on_staging
def test_flaky_api_integration():
response = make_api_call()
assert response.status_code == 200
Пример 2: Декоратор для логирования времени выполнения теста.
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__} executed in {end_time - start_time:.4f} seconds")
return result
return wrapper
@pytest.mark.smoke
@log_execution_time
def test_heavy_report_generation():
# ... логика теста
assert report.is_valid()
Зачем это нужно:
- Кастомизация логики: Добавление специфичных пред- или постусловий для группы тестов.
- Улучшение отчетности: Сбор дополнительных метрик (время, использование памяти).
- Управление flaky-тестами: Логика повторных запусков, более гибкая, чем
@pytest.mark.flaky. - Интеграция: Связка тестов с внешними системами (например, простановка тегов в TestRail).