Skip to content

Class scoped fixture is called multiple times with mutable values and parameterisation #7175

Description

@JSchulte01
  • [ x] a detailed description of the bug or suggestion
  • [ x] output of pip list from the virtual environment you are using
  • [ x] pytest and operating system versions
  • [ x] minimal example if possible

When setting up test parameterisation using a combination of pytest_generate_test hooks and fixture decorators, along with pytest.mark.parameterize decorators I'm seeing inconsistent behaviour with the fixtures which have scope='class'. In the application context these fixtures load large tables of data which takes quite a long time.

When an immutable object is passed as the fixture parameter - the fixtures behave as expected, however when mutable object, like a list is passed, the class fixture gets called repeatedly. The workaround identified in #896 did not seem to make a difference so I have opened a new issue.

If this is expected behaviour or a known bug I would like to add a warning to the docs to make this clear.

Possibly Related

#3678, #896

LSB Release

Distributor ID:	Ubuntu
Description:	Ubuntu 16.04.6 LTS
Release:	16.04
Codename:	xenial

PIP Freeze >>

attrs==19.3.0
importlib-metadata==1.6.0
more-itertools==8.2.0
packaging==20.3
pluggy==0.13.1
py==1.8.1
pyparsing==2.4.7
pytest==5.4.1
six==1.14.0
wcwidth==0.1.9
zipp==3.1.0

Minimum Reproducible Example

import pytest

def pytest_generate_tests(metafunc):

    if 'fixture_a' in metafunc.fixturenames:
        metafunc.parametrize(
            'fixture_a',
            [1, ('a',), ['b']],
            scope='class',
            indirect=True,
        )


@pytest.fixture(scope='session')
def fixture_a(request):
    print('fixture_a CALLED')
    return request.param


class TestExp:

    @pytest.fixture(scope='class')
    def fixture_d(self, fixture_a):
        print('fixture_d CALLED')
        return fixture_a

    def test_func_one(self, fixture_d):
        print(fixture_d)

    @pytest.mark.parametrize(
        'param_a',
        ['*', '+']
    )
    def test_func_two(self, fixture_d, param_a):
        print(fixture_d, ' -> ', param_a)

Output of Test

platform linux -- Python 3.6.8, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- ...
cachedir: .pytest_cache
rootdir: ...
collected 9 items                                                                                                                                                                                          

test_mre.py::TestExp::test_func_one[1] 
fixture_a CALLED
fixture_d CALLED
1
PASSED
test_mre.py::TestExp::test_func_two[1-*] 1  ->  *
PASSED
test_mre.py::TestExp::test_func_two[1-+] 1  ->  +
PASSED

test_mre.py::TestExp::test_func_one[fixture_a1] 
fixture_a CALLED
fixture_d CALLED
('a',)
PASSED
test_mre.py::TestExp::test_func_two[fixture_a1-*] ('a',)  ->  *
PASSED
test_mre.py::TestExp::test_func_two[fixture_a1-+] ('a',)  ->  +
PASSED

test_mre.py::TestExp::test_func_one[fixture_a2] 
fixture_a CALLED
fixture_d CALLED
['b']
PASSED
test_mre.py::TestExp::test_func_two[fixture_a2-*]               <<< ---- Class scoped fixture called twice
fixture_a CALLED
fixture_d CALLED
['b']  ->  *
PASSED
test_mre.py::TestExp::test_func_two[fixture_a2-+] ['b']  ->  +
PASSED

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: help wanteddevelopers would like help from experts on this topictopic: fixturesanything involving fixtures directly or indirectlytopic: parametrizerelated to @pytest.mark.parametrize

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions