Search code examples
pythonunit-testingtestingpytestcode-organization

How to synchronize parametrization across pytest fixtures?


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!


Solution

  • 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