pythonpytestoverloadingfixturespytest-fixtures

How to extend fixture from the base class?


I'm trying to extend a fixture: that means not only overriding, but partially reusing the old one. For example, in the code below the fixture Test.values uses the fixture values and concatenates lists defined in both functions:

import pytest

@pytest.fixture
def values():
    return [1, 2, 3]

class Test:
    @pytest.fixture
    def values(self, values):
        return values + [4, 5, 6]

    def test_values(self, values):
        assert 1 in values
        assert 2 in values
        assert 3 in values
        assert 4 in values
        assert 5 in values
        assert 6 in values

I want to do the same for a fixture defined as a class member:

class Base:
    @pytest.fixture
    def values(self):
        return [1, 2, 3]

class Test(Base):
    @pytest.fixture
    def values(self, values):
        return values + [4, 5, 6]

    def test_values(self, values):
        assert 1 in values
        assert 2 in values
        assert 3 in values
        assert 4 in values
        assert 5 in values
        assert 6 in values

This time I'm getting an error:

E recursive dependency involving fixture 'values' detected

The definition of the second fixture doesn't see the first one, and that is because there is no function overloading in Python. Please advise a way to overcome the issue.

Update Renaming the fixture, as the first two responders have recommended, is not a solution. Consider this usage:

class Base:
    @pytest.fixture
    def values(self):
        return [1, 2, 3]

    def test_values(values, single_value):
        assert single_value in values

class TestA(Base):
    @pytest.fixture
    def values(self, values):
        return values + [4, 5, 6]

    @pytest.fixture(params=[1, 2, 3, 4, 5, 6])
    def single_value(self):
        return request.param

class TestB(Base):
    @pytest.fixture
    def values(self, values):
        return values + [7, 8, 9]

    @pytest.fixture(params=[1, 2, 3, 7, 8, 9])
    def single_value(self):
        return request.param

Here I'm defining a Base class with some basic stuff: some basic values and a test function that is not called in scope of this class, as its name doesn't start with Test. Both TestA and TestB reuse the same test_ function where they override the single_value fixture and try to extend the values. I could also define a TestC(TestA) that would need to extend the values from TestA that are being extended from Base. The idea with having a separate base_values fixture doesn't work here.


Solution

  • I've found a solution. It works if I create a method alias:

    class Base:
        @pytest.fixture
        def values(self):
            return [1, 2, 3]
    
    class Test(Base):
        __basic_values = Base.values
    
        @pytest.fixture
        def values(self, __basic_values):
            return __basic_values + [4, 5, 6]
    
        def test_values(self, values):
            assert 1 in values
            assert 2 in values
            assert 3 in values
            assert 4 in values
            assert 5 in values
            assert 6 in values
    

    This alias respects all the decorators and Pytest really creates a dependency of Test.values to Best.values.