如何将参数传递给 pytest 灯具?



我所有测试的基线是,总会有一辆出租车至少有一名乘客。我可以通过一些基本夹具轻松实现此设置:

from blah import Passenger, Taxi
@pytest.fixture
def passenger():
return Passenger()
@pytest.fixture
def taxi(passenger):
return Taxi(rear_seat=passenger)

测试基线很简单:

def test_taxi_contains_passenger(taxi)
assert taxi.has_passenger()

当我开始需要更复杂的测试设置时,我的问题就会出现。在某些情况下,我需要出租车有多个乘客,而在某些情况下,我需要定义乘客属性。例如:

def test_three_passengers_in_taxi(taxi)
assert taxi.has_passengers(3)
assert taxi.front_passenger_is_not_a_child()

我能够通过为特定测试使用特定的夹具来解决这个问题。对于上述测试,我将创建以下夹具:

@pytest.fixture
def three_passenger_test_setup(taxi)
taxi.add_front_seat_passenger(Passenger(child=False))
taxi.add_rear_seat_passenger(Passenger())
return taxi

我可以将上述夹具传递到我的测试用例中,一切都很花花公子,但是如果我沿着这条路走下去,我最终可能会为每个测试提供一个夹具,感觉应该有一种更有效的方法做到这一点。

有没有办法将参数传递给灯具,以便这些参数可用于创建灯具返回的对象?我应该参数化测试函数吗?夹具?还是我在浪费时间,每次测试的赛程是要走的路吗?

我们可以通过使用一种方法来实现这一点,该方法在夹具中获取参数并从夹具返回该方法。

让我给你看一个例子

@pytest.fixture
def my_fixture():
def _method(a, b):
return a*b
return _method
def test_me(my_fixture):
result1 = my_fixture(2, 3)
assert result1 == 6
result2 = my_fixture(4, 5)
assert result2 == 20

有没有办法将参数传递给灯具,以便这些参数 可用于创建灯具返回的对象? 我应该参数化测试函数吗?

您可以将测试参数化与indirect=True一起使用。 在 pytest 文档中:对特定参数应用间接。 如图所示:https://stackoverflow.com/a/33879151/3858507


夹具?

另一个可能适合您的选项是使用一些使用参数化指定参数的夹具:

@pytest.fixture(params=[3,4])
def number_of_passengers(request):
return request.param

然后从出租车和测试本身访问此夹具:

@pytest.fixture
def taxi(number_of_passengers):
return Taxi(rear_seat=Passenger() * number_of_passengers)
def test_three_passengers_in_taxi(taxi, number_of_passengers)
assert taxi.has_passengers(number_of_passengers)
assert taxi.front_passenger_is_not_a_child()

如果您的测试和断言在你拥有的案例之间非常相似,这种方式很好。


还是我在浪费时间,每次测试的赛程是要走的路吗?

我想说的是,您绝对不应该为每个测试功能创建一个夹具。为此,您可以将设置放在测试中。在您必须为出租车的不同情况做出不同断言的情况下,这实际上是一个可行的替代方案。


最后,您可以使用的另一种可能的模式是出租车工厂。虽然对于您介绍的示例,它不是很有用,但如果需要多个参数并且只有一些参数在更改,您可以创建类似于以下内容的夹具:

from functools import partial
@pytest.fixture
def taxi_factory():
return partial(Taxi, 1, 2, 3)
fixture

只是一个Python 装饰器。

@decorator
def function(args):
...

是花式的

def function(args):
...
function = decorator(function)

所以你也许可以编写自己的装饰器,将你想要装饰的功能包装成你需要的任何内容fixture

def myFixture(parameter):
def wrapper(function):
def wrapped(*args, **kwargs):
return function(parameter, *args, **kwargs)
return wrapped
return pytest.fixture(wrapper)
@myFixture('foo')
def function(parameter, ...):
...

这将像fixture一样,但会将一个值('foo')作为parameter传递给function

TLDR;使用pytest.markrequest装置访问request.keywords

这是一个非常古老的问题,但现有的答案对我不起作用,所以这是我使用 pytest.mark 的解决方案

from blah import Passenger, Taxi
@pytest.fixture
def passenger():
return Passenger()
@pytest.fixture
def taxi(passenger, request):
if "taxi" in request.keywords:
kwargs = request.keywords["taxi"].kwargs
else:
kwargs = dict(rear_seat=passenger)
return Taxi(**kwargs)

# This allows testing the baseline as-is...
def test_taxi_contains_passenger(taxi)
assert taxi.has_passenger()
# and also using pytest.mark to pass whatever kwargs:
@pytest.mark.taxi(rear_seat=[Passenger()] * 3)
def test_three_passengers_in_taxi(taxi)
assert taxi.has_passengers(3)
assert taxi.front_passenger_is_not_a_child()

例如,您可以将 2 个参数传递给具有嵌套函数addition()core()的灯具,如下所示:

import pytest
@pytest.fixture
def addition():
def core(num1, num2):
return num1 + num2
return core
def test(request, addition):
print(addition(2, 3))
print(request.getfixturevalue("addition")(6, 8))
assert True

输出:

$ pytest -q -rP
.                                [100%]
=============== PASSES ================ 
________________ test _________________ 
-------- Captured stdout call --------- 
5
14
1 passed in 0.10s

相关内容

  • 没有找到相关文章

最新更新