我有一个装饰器,可以将参数注入到函数中,效果很好。然而,当我想在测试函数上使用它时,pytest 固定装置就会变得混乱。有什么办法可以解决吗
看这个例子:
@pytest.fixture()
def my_fixture():
...
def auto_asset(name, path: Optional[Path] = None, return_path: bool = True):
"""
Decorator to automatically retrieve asset and insert path into decorated functions
signature (default).
Args:
name:
path:
return_path: insert return path as "path_{name}" in decorated function's signature
Examples:
@auto_asset("bead_cal")
def some_fn(path_bead_cal: Path):
pass
"""
def wrap_fn(fn):
@wraps(fn)
def wrapped_fn(*args, **kwargs):
p = load_asset(name=name, path=path)
if return_path:
# add asset path to decorated functions signature
kwargs.update({f"path_{name}": p})
return fn(*args, **kwargs)
return wrapped_fn
return wrap_fn
@auto_asset("calibration", return_path=True)
def test_something(path_calibration, my_fixture):
...
为此我直接得到了
_pytest.fixtures.FixtureLookupError: ('path_calibration', <FixtureRequest for <Function test_something>>)
即使在装饰器实现中设置断点也不起作用。
除非你真的需要保持原来的装饰器原样,否则我只需将其重写为间接 Pytest 固定装置。简化示例(不是装饰器的完整重写):
import pytest
@pytest.fixture()
def my_fixture():
...
@pytest.fixture()
def auto_asset(request):
p = load_asset(name=request.param["name"], path=request.param["path"])
...
@pytest.mark.parametrize("auto_asset", ({"name": "calibration", "path": "", "return_path": True},), indirect=True)
def test_something(auto_asset, my_fixture):
...
为了使其更复杂,夹具实际上可以构建并返回一个函数:
import pytest
from typing import Callable
from functools import partial
@pytest.fixture()
def my_fixture():
...
@pytest.fixture()
def auto_asset(request):
name = request.param["name"]
p = load_asset(name=name, path=request.param["path"])
def _(*args, **kwargs):
...
return partial(_, **{f"path_{name}": p})
@pytest.mark.parametrize("auto_asset", ({"name": "calibration", "path": "", "return_path": True},), indirect=True)
def test_something(auto_asset: Callable, my_fixture):
...