Как заставить фикстуры pytest работать с декорированными функциями?
Проблема с использованием декоратора в тестах с фикстурами в py.test
Я пытаюсь использовать декоратор для тестовой функции, которая принимает фикстуру в качестве аргумента, и сталкиваюсь с ошибкой. Вот минимальный пример кода, где я демонстрирую проблему:
import functools
import pytest
def deco(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@pytest.fixture
def x():
return 0
@deco
def test_something(x):
assert x == 0
При запуске тестов я получаю следующую ошибку:
TypeError: test_something() takes exactly 1 argument (0 given).
Похоже, что декоратор как-то мешает передаче фикстуры в тестовую функцию. Есть ли способ исправить это, желательно без значительных изменений в декораторе? Обратите внимание, что декоратор используется и вне тестового кода.
Буду признателен за помощь!
2 ответ(ов)
Функция-фикстура зависит от сигнатуры тестовой функции.
Если у вас есть возможность изменить сигнатуру обертки, то это будет работать:
def deco(func):
@functools.wraps(func)
def wrapper(x):
return func(x)
return wrapper
Если вы не можете изменить ее, создайте другой декоратор:
def deco(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
def deco_x(func):
@functools.wraps(func)
def wrapper(x):
return func(x)
return wrapper
И используйте декоратор deco_x
для функции test_something
:
@deco_x
@deco
def test_something(x):
assert x == 0
Таким образом, вы сможете обрабатывать тестовую функцию с нужной сигнатурой, не изменяя основной декоратор.
Если вы используете фикстуру pytest с декоратором и необходимо передать данные в декоратор, вы можете сделать это следующим образом:
import pytest
@pytest.fixture(scope="session")
def data(request):
data = list(range(10))
yield data
def decorator_with_variable_and_fixture(whatever):
def wrap(test_func):
def wrapper(data):
mod = whatever.lower()[::-1]
test_func(data, mod)
return wrapper
return wrap
@decorator_with_variable_and_fixture(whatever='SOMETHING!')
def test_decorator_with_variable_and_fixture(data, whatever):
for i in data:
print(whatever[i]*(i+1))
assert whatever == '!gnihtemos'
assert data == list(range(10))
Обратите внимание, как data
передается в функцию wrapper
— таким образом, подход с фиктурами pytest работает корректно.
Это особенно полезно, если вам нужно передавать сессию PySpark, используя декоратор для выполнения другой функциональности.
Как правильно проверить, что исключение возникает в pytest?
Работают ли параметризованные тесты pytest с тестами на основе классов unittest?
Где размещать юнит-тесты на Python? [закрыто]
Python - объект MagicMock не может быть использован в выражении 'await'
Способ вывести имя теста PyUnit в методе setup()