pytest:使用 pytest.mark.parametrize 和间接参数化将关键字 arg 传递给 fixture
pytest: passing keyword arg to fixture using pytest.mark.parametrize with indirect parameterization
我有一个 pytest.fixture
,它有一个位置参数和一个关键字参数。
根据 Pass a parameter to a fixture function,可以使用 pytest.mark.parametrize
将 args 传递给 fixture,并将 indirect
arg 设置为 fixture 的名称。
请看下面的示例代码。
import pytest
class Foo:
def __init__(self, a: str, b: str):
self.a = a
self.b = b
@pytest.fixture
def a() -> str:
return "alphabet"
@pytest.fixture
def foo_obj(a: str, b: str = "bar") -> Foo:
return Foo(a, b)
@pytest.mark.parametrize("foo_obj", [("applesauce", "baz")], indirect=["foo_obj"])
def test_thing(foo_obj) -> None:
assert foo_obj.a == "applesauce"
assert foo_obj.b == "baz"
此测试当前失败:"applesauce"
和 "baz"
未传递到夹具 foo_obj
。
我的问题:
- 我在将 args 传递给夹具时做错了什么
foo_obj
?
- 是否可以在
pytest.mark.parametrize
装饰器调用中只输入 kwarg b
?
- 注意:我对按照此处的建议包装夹具不感兴趣:Can I pass arguments to pytest fixtures?
版本
Python==3.8.5
pytest==6.0.1
我认为您在这里混合了两件事:通过 request.params
将参数传递给夹具,以及将夹具基于另一个(或多个)夹具。
要在夹具中使用 mark.parametrize
中使用的参数,您必须从 request.params
中获取它们,如您的链接问题所示:
@pytest.fixture
def foo_obj(request) -> Foo:
return Foo(request.param[0], request.param[1])
你正在做的,是将 foo_obj
基于固定装置 a
,意思是,a
是那个固定装置的结果(例如它总是 "a"
), 和一个常量参数 b
。两者都与 parametrize
设置的值无关 - 这些设置在 request.params
中,如上所示。
讨论隐式间接参数化的 put me on the scent of this answer。
@pytest.fixture
def foo_obj(a: str, b: str) -> Foo: # Note: b was changed to positional arg
print("hi")
return Foo(a, b)
@pytest.mark.parametrize("a, b", [("applesauce", "baz")])
def test_thing(foo_obj) -> None:
assert foo_obj.a == "applesauce"
assert foo_obj.b == "baz"
上述情况测试通过。
似乎这种隐式间接参数化可以用于位置参数,但不能用于关键字参数。例如,如果 b
作为关键字参数保留在夹具 foo_obj
中,pytest 将失败并显示消息:In test_thing: function uses no argument 'b'
.
我想知道,是否可以通过这种方式对关键字参数进行参数化?
第二次尝试使用关键字 arg
我决定再次尝试拉动 and also this answer:
@pytest.fixture
def a() -> str:
return "alphabet"
@pytest.fixture
def foo_obj(request, a) -> Foo:
return Foo(request.param.get("a", a), request.param.get("b", "bar"))
@pytest.mark.parametrize("foo_obj", [dict(a="applesauce", b="baz")], indirect=True)
def test_thing(foo_obj) -> None:
# Override both defaults, passes
assert foo_obj.a == "applesauce"
assert foo_obj.b == "baz"
@pytest.mark.parametrize("foo_obj", [dict(b="baz")], indirect=True)
def test_thing_only_b(foo_obj) -> None:
# Use the default for a
assert foo_obj.a == "alphabet"
assert foo_obj.b == "baz"
这有效!我觉得它与接受两个参数的 foo_obj
夹具有点令人费解,有时它会使用一个或另一个。
我有一个 pytest.fixture
,它有一个位置参数和一个关键字参数。
根据 Pass a parameter to a fixture function,可以使用 pytest.mark.parametrize
将 args 传递给 fixture,并将 indirect
arg 设置为 fixture 的名称。
请看下面的示例代码。
import pytest
class Foo:
def __init__(self, a: str, b: str):
self.a = a
self.b = b
@pytest.fixture
def a() -> str:
return "alphabet"
@pytest.fixture
def foo_obj(a: str, b: str = "bar") -> Foo:
return Foo(a, b)
@pytest.mark.parametrize("foo_obj", [("applesauce", "baz")], indirect=["foo_obj"])
def test_thing(foo_obj) -> None:
assert foo_obj.a == "applesauce"
assert foo_obj.b == "baz"
此测试当前失败:"applesauce"
和 "baz"
未传递到夹具 foo_obj
。
我的问题:
- 我在将 args 传递给夹具时做错了什么
foo_obj
? - 是否可以在
pytest.mark.parametrize
装饰器调用中只输入 kwargb
?- 注意:我对按照此处的建议包装夹具不感兴趣:Can I pass arguments to pytest fixtures?
版本
Python==3.8.5
pytest==6.0.1
我认为您在这里混合了两件事:通过 request.params
将参数传递给夹具,以及将夹具基于另一个(或多个)夹具。
要在夹具中使用 mark.parametrize
中使用的参数,您必须从 request.params
中获取它们,如您的链接问题所示:
@pytest.fixture
def foo_obj(request) -> Foo:
return Foo(request.param[0], request.param[1])
你正在做的,是将 foo_obj
基于固定装置 a
,意思是,a
是那个固定装置的结果(例如它总是 "a"
), 和一个常量参数 b
。两者都与 parametrize
设置的值无关 - 这些设置在 request.params
中,如上所示。
讨论隐式间接参数化的
@pytest.fixture
def foo_obj(a: str, b: str) -> Foo: # Note: b was changed to positional arg
print("hi")
return Foo(a, b)
@pytest.mark.parametrize("a, b", [("applesauce", "baz")])
def test_thing(foo_obj) -> None:
assert foo_obj.a == "applesauce"
assert foo_obj.b == "baz"
上述情况测试通过。
似乎这种隐式间接参数化可以用于位置参数,但不能用于关键字参数。例如,如果 b
作为关键字参数保留在夹具 foo_obj
中,pytest 将失败并显示消息:In test_thing: function uses no argument 'b'
.
我想知道,是否可以通过这种方式对关键字参数进行参数化?
第二次尝试使用关键字 arg
我决定再次尝试拉动
@pytest.fixture
def a() -> str:
return "alphabet"
@pytest.fixture
def foo_obj(request, a) -> Foo:
return Foo(request.param.get("a", a), request.param.get("b", "bar"))
@pytest.mark.parametrize("foo_obj", [dict(a="applesauce", b="baz")], indirect=True)
def test_thing(foo_obj) -> None:
# Override both defaults, passes
assert foo_obj.a == "applesauce"
assert foo_obj.b == "baz"
@pytest.mark.parametrize("foo_obj", [dict(b="baz")], indirect=True)
def test_thing_only_b(foo_obj) -> None:
# Use the default for a
assert foo_obj.a == "alphabet"
assert foo_obj.b == "baz"
这有效!我觉得它与接受两个参数的 foo_obj
夹具有点令人费解,有时它会使用一个或另一个。