我可以将参数传递给 pytest 固定装置吗?

Posted

技术标签:

【中文标题】我可以将参数传递给 pytest 固定装置吗?【英文标题】:Can I pass arguments to pytest fixtures? 【发布时间】:2017-11-24 10:28:00 【问题描述】:

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

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

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

有没有办法将参数传递给夹具,以便这些参数可以用于创建夹具返回的对象?我应该参数化测试功能吗?夹具?还是我在浪费时间,每次测试都需要一个固定装置?

【问题讨论】:

【参考方案1】:

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

【讨论】:

【参考方案2】:

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

您可以通过indirect=True 使用测试参数化。 在 pytest 文档中:Apply indirect on particular arguments。 如此处所示:https://***.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()

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


或者我是在浪费时间,每次测试都需要一个固定装置吗?

我会说你绝对不应该为每个测试函数创建一个fixture。为此,您可以将设置放入测试中。如果您必须为出租车的不同情况做出不同的断言,这实际上是一个可行的替代方案。


最后,您可以使用的另一种可能模式是出租车工厂。虽然对于您提供的示例来说它不是很有用,但如果需要多个参数并且只有一些参数在更改,您可以创建一个类似于以下的固定装置:

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

【讨论】:

【参考方案3】:

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

让我给你看一个例子

@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

【讨论】:

我喜欢这个,它非常实用 你能再解释一下吗?如果 my_fixture() 不带任何参数,为什么我可以将参数传递给它?另外,如果我在测试用例中使用多个夹具,但我只想将参数传递给其中一个,会发生什么情况? @JacobPavlock 这样想。当您将fixture 函数my_fixture 作为参数传递给test_me 时,它会被调用。返回值存储在my_fixture 参数中。因此,当您在 test_me 中调用 my_fixture 时,您实际上是在调用返回值 这节省了我很多时间。谢谢!

以上是关于我可以将参数传递给 pytest 固定装置吗?的主要内容,如果未能解决你的问题,请参考以下文章

我可以将类型作为参数传递给这个函数吗?

将固定大小的特征矩阵作为参数传递给调用动态大小矩阵的函数

我可以通过 add_action 将参数传递给我的函数吗?

在scala中我可以将重复的参数传递给其他方法吗?

我们可以将参数传递给 dart 中的引用方法吗?

Matlab:将更多参数传递给`nlinfit`函数