1

Similar to this question: py.test: Pass a parameter to a fixture function, however, we want to also paramaterise inputs to the test.

For example (this is simplified version of what I want to do):

import pytest


def person_says(name, age):
    return f"{name} is {age}"


@pytest.fixture
def add_surname(request):
    surname = request.param
    return f'Mike {surname}'


NAME1 = "Johnson"
AGE1 = "13"
OUTPUT1 = "Mike Johnson is 13"
NAME2 = "Liam"
AGE2 = "21"
OUTPUT2 = "Mike Liam is 21"

I want to pass something like this:

@pytest.mark.parametrize('add_surname,age,expected',
                         [[NAME1, AGE1, OUTPUT1], 
                          [NAME2, AGE2, OUTPUT2]],
                         indirect=True)
def test_person_says(add_surname, age, expected):
    name = add_surname
    output = person_says(name, age)
    assert expected == output

But that doesn't work, as it looks for the fixture age, which doesn't exist.


Using multiple decorators does all 4 combinations.

@pytest.mark.parametrize('age,expected', [[AGE1, OUTPUT1], [AGE2, OUTPUT2]])
@pytest.mark.parametrize('add_surname', [NAME1, NAME2], indirect=True)
def test_person_says(add_surname, age, expected):
    name = add_surname
    output = person_says(name, age)
    assert expected == output

Results:

Expected :Mike Liam is 21        Actual   :Mike Johnson is 21  # FAIL
Expected :Mike Johnson is 13     Actual   :Mike Johnson is 13  # Pass
Expected :Mike Johnson is 13     Actual   :Mike Liam is 13     # FAIL
Expected :Mike Liam is 21        Actual   :Mike Liam is 21     # Pass

What is the best way of doing it?

A H
  • 2,164
  • 1
  • 21
  • 36

1 Answers1

1

Besides of a boolean, indirect can take a list of input names, so indirect parametrization via fixtures is only applied to those inputs. Example:

@pytest.mark.parametrize('x, y, z', [('spam', 'eggs', 'bacon')], indirect=['x', 'y'])

x and y are parametrized indirectly, so spam and eggs will be passed through x and y fixtures, but z is parametrized directly, so bacon will be used as plain input. In your case:

@pytest.mark.parametrize('add_surname,age,expected',
                         [[NAME1, AGE1, OUTPUT1], 
                         [NAME2, AGE2, OUTPUT2]],
                         indirect=['add_surname'])

will do the trick.

hoefling
  • 59,418
  • 12
  • 147
  • 194