How to synchronize parametrization across pytest fixtures?

Viewed 252

I have two fixtures A and B with the same params argument passed to pytest.fixture(). Additionally, B takes A as an argument:

import pytest

@pytest.fixture(params=[1, 2])
def A(request):
    if request.param == 1:
        # do stuff to get matrix_1
        return matrix_1
    if request.param == 2:
        # do stuff to get matrix_2
        return matrix_2

@pytest.fixture(params=[1, 2])
def B(request, A):
    if request.param == 1:
        # do stuff with A to get matrix_3
        return matrix_3
    if request.param == 2:
        # do stuff with A to get matrix_4
        return matrix_4

I also have a function test_method, which takes fixtures B and my_class (a fixture that returns a MyClass() instance) as arguments and tests a method of my_class. The method takes B as an argument. I don't think this information necessarily matters for the question, it is just here for context:

from my_module import MyClass

@pytest.fixture
def my_class():
    return MyClass()

def test_method(my_class, B):
    # do stuff to get the expected value
    actual = my_class.method(B)
    assert actual == expected

The problem is that the whole construct only makes sense if A and B have the same params at every point in time, i.e. A cannot have request.param = 1, when B has request.param = 2. These variables are not intended to be used otherwise in the program, and the tested code breaks if they are.

Is there a way to share, or synchronize parametrization across fixtures? Or redesign the code somehow, so that it's not a problem? Thanks!

1 Answers

Updated after the comments by the OP:

In your code, you create four tests instead of two, two of them identical. You can use a base fixture that just provides the parameters and not parameterize the derived fixtures instead:

@pytest.fixture(params=[1, 2])
def Base(request):
    return request.param

@pytest.fixture
def A(Base):
    if Base == 1:
        return value_1
    if Base == 2:
        return value_2


@pytest.fixture
def B(Base):
    if Base == 1:
        return value_3
    if Base == 2:
        return value_4
Related