5

I would like to pass in an argument to my pytest fixture so I don't need 10 different fixtures when the fixtures are 90% the same.

The simplest example of what I'd like to achieve:

@pytest.mark.parametrize('foo', [a=1])
def test_args(tmp_path, foo):
    assert foo == 3

@pytest.fixture
def foo(tmp_path, a, b=2):
    return a + b

Is there a way to mark a and b as arguments and not other fixtures? Or maybe the best way to do this is somehow by defining a function instead of a fixture?

I put the tmp_path fixture in there to ensure the parametrization is explicit and allows for more than one fixture to be used.

It's worth pointing out that

@pytest.fixture
def foo(request):
    return request.param[0] + request.param[1]


@pytest.mark.parametrize('foo', [(1, 2)], indirect=True)
def test_args(tmp_path, foo):
    assert foo == 3

works, (as defined in the docs), but is not what I'm looking for. I'm wondering if something more similar to my given code will work. I'd like to be able to pass arguments by name, specify default values for arguments, etc.

I've seen this similar stackoverflow question, which seems to indicate that this feature is supported by pytest(?), but its answers seem to just further confusion and none of them seem to work for the case I presented.

Jacob Pavlock
  • 673
  • 8
  • 20
  • I think the indirect parametrization you show in your example is the nearest pytest has for that - though I would love to be wrong. – MrBean Bremen Aug 15 '20 at 12:53
  • What is `[a=1]` supposed to mean? That's not a valid Python syntax. _Is there a way to mark a and b as arguments and not other fixtures?_ Not really, due to special treatment of fixture args. `pytest` treats all args that are positional, aren't bound by `functools.partial` or replaced by `unittest.mock` as placeholders for other fixtures. `a` in your example thus should be a fixture, or `pytest` will fail. – hoefling Aug 15 '20 at 21:38
  • @hoefling that code example isn't supposed to work. Rather I'm just trying to get the point of my question across that I'd like to specify arguments by name. – Jacob Pavlock Aug 15 '20 at 21:42

1 Answers1

9

I was able to achieve what I wanted with fixture factories

@pytest.fixture
def foo(tmp_path):
    def _foo(a: int, b: int = 2):
        return a + b

    return _foo

def test_args(tmp_path, foo):
    bar = foo(a=1)
    assert bar == 3
Jacob Pavlock
  • 673
  • 8
  • 20