How to add a fixture as part of mark.parametrize in a pytest?

Question:

I want to be able to parametrize a fixture list and list within a list for a unit-test like in the sample code below, the problem is that the fixtures are not recognized in the "pytest.mark.parametrize" annotation. What should I do?

@pytest.fixture(scope="session")
def simple_list() -> list[int]:
    return [1, 2, 3]


@pytest.fixture(scope="session")
def list_within_a_list() -> list[list[int]]:
    return [[1, 2, 3], [3, 4, 5], [5, 6, 7]]


@pytest.mark.parametrize(
    "simple_list_element, list_within_a_list_first_element, list_within_a_list_second_element, list_within_a_list_third_element",
    itertools.product(
        simple_list,
        *list_within_a_list,
    ),
)
def test_check_settings(
    simple_list_element,
    list_within_a_list_first_element,
    list_within_a_list_second_element,
    list_within_a_list_third_element,
):
    ...
Asked By: Jordan Jordanovski

||

Answers:

I think this should do what you want:

@pytest.fixture(scope="session")
def simple_list() -> list[int]:
    return [1, 2, 3]


@pytest.fixture(scope="session")
def list_within_a_list() -> list[list[int]]:
    return [[1, 2, 3], [3, 4, 5], [5, 6, 7]]


@pytest.fixture(scope="session")
def list_within_a_list_first(list_within_a_list) -> list[int]:
    return list_within_a_list[0]


@pytest.fixture(scope="session")
def list_within_a_list_second(list_within_a_list) -> list[int]:
    return list_within_a_list[1]


@pytest.fixture(scope="session")
def list_within_a_list_third(list_within_a_list) -> list[int]:
    return list_within_a_list[2]


@pytest.mark.parametrize("simple_list_fixture", ["simple_list"])
@pytest.mark.parametrize("list_within_a_list_first_fixture", ["list_within_a_list_first"])
@pytest.mark.parametrize("list_within_a_list_second_fixture", ["list_within_a_list_second"])
@pytest.mark.parametrize("list_within_a_list_third_fixture", ["list_within_a_list_third"])
def test_check_settings(
    simple_list_fixture,
    list_within_a_list_first_fixture,
    list_within_a_list_second_fixture,
    list_within_a_list_third_fixture,
):
    simple_list_element = request.getfixturevalue(simple_list_fixture)
    list_within_a_list_first_element = request.getfixturevalue(list_within_a_list_first_fixture)
    list_within_a_list_second_element = request.getfixturevalue(list_within_a_list_second_fixture)
    list_within_a_list_third_element = request.getfixturevalue(list_within_a_list_third_fixture)
    ...

Applying the parametrize decorator multiple times gives you the product of the params.

If list_within_a_list returns a variable number of elements or lots of elements and you can’t manually derive the per-element fixtures from it then I think you’d need to look into using subtests, via pytest-subtests lib.

In that case I think you could do this:

@pytest.fixture(scope="session")
def simple_list() -> list[int]:
    return [1, 2, 3]


@pytest.fixture(scope="session")
def list_within_a_list() -> list[list[int]]:
    return [[1, 2, 3], [3, 4, 5], [5, 6, 7]]


@pytest.mark.parametrize(
    "simple_list_fixture, list_within_a_list_fixture",
    ["simple_list", "list_within_a_list"]
)
def test_check_settings(
    subtests,
    simple_list_fixture,
    list_within_a_list_fixture,
):
    simple_list_element = request.getfixturevalue(simple_list_fixture)
    list_within_a_list_elements = request.getfixturevalue(list_within_a_list_fixture)
    values_gen = itertools.product(simple_list_element, *list_within_a_list_elements)
    for i, values in enumerate(values_gen):
        with subtests.test(msg=f"case {i}", i=i, values=values):
            simple_el, *list_els = values
            ...
Answered By: Anentropic
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.