Can I pass arguments to pytest fixtures?

妖精的绣舞 提交于 2019-12-03 08:15:44

We can do this by using a method that takes args within a fixture and return the method from the fixture.

let me show you an example

@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

Is there a way to pass arguments to a fixture so that those arguments can be used in creating the object the fixture returns? Should I be parameterizing the test function?

You can use test parametrization with indirect=True. In the pytest docs: Apply indirect on particular arguments. As displayed here: https://stackoverflow.com/a/33879151/3858507


The fixture?

Another option that might suit you is using some fixture that specifies the argument using parametrization:

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

and then accessing this fixture from the taxi and the test itself:

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

This way is good if your tests and asserts are very similar between the cases you have.


Or am I wasting time and is a fixture per test the way to go?

I'd say you definitely shouldn't create a fixture for every test function. For that, you can just put the setup inside the test. This is actually a viable alternative in the case that you have to make different asserts for different cases of the taxi.


And finally another possible pattern you can use is a taxi factory. While for the example you've presented its not quite useful, if multiple parameters are required and only some are changing you can create a fixture similar to the following:

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

That fixture is just a Python decorator.

@decorator
def function(args):
  ...

is fancy for

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

So you just might be able to write your own decorator, wrapping up the function you want to decorate in whatever you need and the 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, ...):
  ...

This will act like the fixture but will pass a value ('foo') as parameter to function.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!