Skip to content

run class scoped parametrized fixture's dependency fixture's teardown after each test class iteration #9427

@marshall7m

Description

@marshall7m

Problem:

The conftest.py fixture's setup/teardown is not executed after each test class iteration.

When running pytest test_foo.py --setup-plan, the SETUP C conf_fixt is only executed before the first parametrized class iteration, and TEARDOWN C conf_fixt is only executed after the last parameterized class iteration is complete.

Related Files:

conftest.py

import pytest
from random import randint

@pytest.fixture(scope='class')
def conf_fixt():
    y = randint(1, 100000)
    yield y
    print(f'teardown: {y}')

test_foo.py

from buildspecs.foo.conftest import conf_fixt
import pytest

@pytest.mark.parametrize("scenario", [
    ("scenario_1"),
    ("scenario_2")
], scope='class')

class TestZoo:
    @pytest.fixture(scope="class")
    def scenario_1(self):
        yield 'scenario_1'

    @pytest.fixture(scope="class")
    def scenario_2(self):
        yield 'scenario_2'

    def test_scenario(self, scenario, request, conf_fixt):
        print(f'scenario value: {request.getfixturevalue(scenario)}')
        print(f'conf_fixt value: {conf_fixt}')

    def test_other(self, scenario, request, conf_fixt):
        print(f'scenario value: {request.getfixturevalue(scenario)}')
        print(f'conf_fixt value: {conf_fixt}')

Actual:

pytest test_foo.py

platform linux -- Python 3.9.8, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /src
plugins: mock-3.6.1
collected 4 items                                                                                   

test_foo.py scenario value: scenario_1
conf_fixt value: 111111
.scenario value: scenario_1
conf_fixt value: 111111
.scenario value: scenario_2
conf_fixt value: 111111
.scenario value: scenario_2
conf_fixt value: 111111
.teardown: 111111

pytest test_foo.py --setup-plan

platform linux -- Python 3.9.8, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /src
plugins: mock-3.6.1
collected 2 items                                                                                   

test_foo.py 
      SETUP    C conf_fixt
      SETUP    C scenario['scenario_1']
        buildspecs/foo/test_foo.py::TestZoo::test_scenario[scenario_1] (fixtures used: conf_fixt, request, scenario)
      TEARDOWN C scenario['scenario_1']
      SETUP    C scenario['scenario_2']
        buildspecs/foo/test_foo.py::TestZoo::test_scenario[scenario_2] (fixtures used: conf_fixt, request, scenario)
      TEARDOWN C scenario['scenario_2']
      TEARDOWN C conf_fixt

Expected:

pytest test_foo.py

platform linux -- Python 3.9.8, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /src
plugins: mock-3.6.1
collected 4 items                                                                                   

test_foo.py scenario value: scenario_1
conf_fixt value: 111111
.scenario value: scenario_1
conf_fixt value: 111111
.teardown: 111111
.scenario value: scenario_2
conf_fixt value: 222222
.scenario value: scenario_2
conf_fixt value: 222222
.teardown: 222222

pytest test_foo.py --setup-plan

platform linux -- Python 3.9.8, pytest-6.2.5, py-1.11.0, pluggy-1.0.0
rootdir: /src
plugins: mock-3.6.1
collected 2 items                                                                                   

test_foo.py 
      SETUP    C conf_fixt
      SETUP    C scenario['scenario_1']
        buildspecs/foo/test_foo.py::TestZoo::test_scenario[scenario_1] (fixtures used: conf_fixt, request, scenario)
      TEARDOWN C scenario['scenario_1']
      ###Expected teardown
      TEARDOWN C conf_fixt 
      ###
      SETUP    C scenario['scenario_2']
        buildspecs/foo/test_foo.py::TestZoo::test_scenario[scenario_2] (fixtures used: conf_fixt, request, scenario)
      TEARDOWN C scenario['scenario_2']
      TEARDOWN C conf_fixt

Attempts:

Add the conf_fixt fixture to the pytest.marks.parametrize() decorator like so:

import pytest

@pytest.mark.parametrize("scenario,conf_fixt_param", [
    ("scenario_1", "conf_fixt"),
    ("scenario_2", "conf_fixt")
], scope='class')

class TestZoo:
    @pytest.fixture(scope="class")
    def scenario_1(self):
        yield 'scenario_1'

    @pytest.fixture(scope="class")
    def scenario_2(self):
        yield 'scenario_2'

    def test_scenario(self, scenario, request, conf_fixt_param):
        print(f'scenario value: {request.getfixturevalue(scenario)}')
        print(f'conf_fixt value: {request.getfixturevalue(conf_fixt_param)}')


    def test_other(self, scenario, request, conf_fixt_param):
        print(f'scenario value: {request.getfixturevalue(scenario)}')
        print(f'conf_fixt value: {request.getfixturevalue(conf_fixt_param)}')

Same Actual and Expected output as the original problem.

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: fixturesanything involving fixtures directly or indirectly

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions