我可以将参数传递给pytest灯具吗?

时间:2017-06-21 13:22:51

标签: python pytest fixtures

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

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

我可以将上面的灯具传递到我的测试用例中,一切都很花哨,但是如果我沿着这条路走下去,我可能会为每次测试找到一个夹具,感觉应该有一个更有效的方法。

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

3 个答案:

答案 0 :(得分:12)

我们可以通过使用一个方法来实现这一点,该方法在一个fixture中获取args并从fixture中返回该方法。

让我给你看一个例子

@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

答案 1 :(得分:7)

  

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

您可以使用indirect=True进行测试参数化。 在pytest docs中:Apply indirect on particular arguments。 如下所示:https://stackoverflow.com/a/33879151/3858507

  

夹具?

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

@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)

答案 2 :(得分: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