参数注入装饰器和 pytest 装置的相互作用

问题描述 投票:0回答:1

我有一个装饰器,可以将参数注入到函数中,效果很好。然而,当我想在测试函数上使用它时,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>>)

即使在装饰器实现中设置断点也不起作用。

python pytest decorator fixtures
1个回答
0
投票

除非你真的需要保持原来的装饰器原样,否则我只需将其重写为间接 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):
    ...
© www.soinside.com 2019 - 2024. All rights reserved.