#python #testing #pytest #fixtures #monkeypatching
Вопрос:
Допустим, у меня есть очень простой декоратор для ведения журнала:
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"{func.__name__} ran with args: {args}, and kwargs: {kwargs}")
result = func(*args, **kwargs)
return result
return wrapper
Я могу добавить этот декоратор в каждый модульный тест pytest индивидуально:
@my_decorator
def test_one():
assert True
@my_decorator
def test_two():
assert 1
Как я могу автоматически добавлять этот декоратор в каждый модульный тест pytest, чтобы мне не приходилось добавлять его вручную? Что делать, если я хочу добавить его в каждый модульный тест в файле? Или в модуле?
Мой вариант использования-обернуть каждую тестовую функцию профилировщиком SQL, поэтому неэффективный код ORM вызывает ошибку. Использование прибора pytest должно сработать, но у меня есть тысячи тестов, поэтому было бы неплохо автоматически применять оболочку вместо добавления прибора в каждый отдельный тест. Кроме того, может быть один или два модуля, которые я не хочу профилировать, поэтому было бы полезно иметь возможность отказаться или отказаться от всего файла или модуля.
Комментарии:
1. Можете ли вы предоставить некоторую информацию о вашем случае использования? Стандартным способом в pytest было бы использование автоматического приспособления, хотя, может быть, вы хотите сделать что-то, что невозможно сделать с помощью приспособления?
2. @MrBeanBremen только что обновил вопрос выше с моим вариантом использования
Ответ №1:
При условии, что вы можете переместить логику в приспособление, как указано в вопросе, вы можете просто использовать приспособление автоматического использования, определенное на верхнем уровне conftest.py
.
Чтобы добавить возможность отказаться от некоторых тестов, вы можете определить маркер, который будет добавлен в тесты, которые не должны использовать прибор, и проверить этот маркер в приборе, например, что-то вроде этого:
conftest.py
import pytest
def pytest_configure(config):
config.addinivalue_line(
"markers",
"no_profiling: mark test to not use sql profiling"
)
@pytest.fixture(autouse=True)
def sql_profiling(request):
if not request.node.get_closest_marker("no_profiling"):
# do the profiling
yield
test.py
import pytest
def test1():
pass # will use profiling
@pytest.mark.no_profiling
def test2():
pass # will not use profiling
Как указал @hoefling, вы также можете отключить приспособление для всего модуля, добавив:
pytestmark = pytest.mark.no_profiling
в модуле. Это добавит маркер ко всем содержащимся тестам.
Комментарии:
1. Хороший ответ — это также позволяет отключить светильник для всего модуля, добавив параметр модуля
pytestmark = pytest.mark.no_profiling
. Таким образом, никакой декоратор на заказ вообще не должен быть нужен!2. Я получил следующую ошибку:
ValueError: unknown configuration value: 'no_profiling'
— но после того, как я удалилpytest_configure
, все работало идеально. Спасибо!3. Ах, извините — я допустил ошибку в синтаксисе регистрации маркеров, исправил ее сейчас. Без этого вы получите предупреждение о неизвестном маркере.