pytest-dev / pytest-dev/pytest

Fixture teardown is called during setup of the next test

Open
#9,287 8 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

topic: fixtures topic: parametrize type: bug
Dominant language
Python
Stars
14.5k
Forks
3.4k
Avg merge
2d 9h
Merged PRs (30d)
35

Description

When having 2 tests which call module-scoped yield fixtures and using parametrize, teardown is done between tests, during the setup of the 2nd test (pytest_runtest_setup) and not during pytest_runtest_teardown.
Running with pytest 6.2.5
Is there a way to achieve the desired flow (i.e teardown is done when exiting the fixture, as described below in the flow without parametrize) while using parameterized?

Example test:

import pytest

import logging

LOGGER = logging.getLogger(__name__)


@pytest.fixture(scope="module")
def fix1():
    LOGGER.info("++++++++++++++++++++++++++fix1")
    yield
    LOGGER.info("t1")


@pytest.fixture(scope="module")
def fix2():
    LOGGER.info("++++++++++++++++++++++++++fix2")
    yield
    LOGGER.info("t2")


@pytest.mark.parametrize("fix1, fix2",
    [
    pytest.param(1, 2)
    ],
    indirect=True)
def test1(fix1, fix2):
    LOGGER.info("in test")


def test2(fix1, fix2):
    LOGGER.info("in test")

Output:

tests.test_ruty 2021-11-08 20:27:55 INFO ++++++++++++++++++++++++++fix1
tests.test_ruty 2021-11-08 20:27:55 INFO ++++++++++++++++++++++++++fix2
------------------------------------------------------------------------------------------------------ CALL ------------------------------------------------------------------------------------------------------
tests.test_ruty 2021-11-08 20:27:55 INFO in test

TEST: test1[1-2] STATUS: PASSED
.---------------------------------------------------------------------------------------------------- TEARDOWN ----------------------------------------------------------------------------------------------------

__________________________________________________________________ 1 of 2 completed, 1 Pass, 0 Fail, 0 Skip, 0 XPass, 0 XFail, 0 Error, 0 ReRun ___________________________________________________________________

tests/test_ruty.py 
------------------------------------------------------------------------------------------------------ test2 ------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------ SETUP ------------------------------------------------------------------------------------------------------
tests.test_ruty 2021-11-08 20:27:55 INFO t1
tests.test_ruty 2021-11-08 20:27:55 INFO ++++++++++++++++++++++++++fix1
tests.test_ruty 2021-11-08 20:27:55 INFO t2
tests.test_ruty 2021-11-08 20:27:55 INFO ++++++++++++++++++++++++++fix2
------------------------------------------------------------------------------------------------------ CALL ------------------------------------------------------------------------------------------------------
tests.test_ruty 2021-11-08 20:27:55 INFO in test

TEST: test2 STATUS: PASSED
.---------------------------------------------------------------------------------------------------- TEARDOWN ----------------------------------------------------------------------------------------------------
tests.test_ruty 2021-11-08 20:27:55 INFO t2
tests.test_ruty 2021-11-08 20:27:55 INFO t1

__________________________________________________________________ 2 of 2 completed, 2 Pass, 0 Fail, 0 Skip, 0 XPass, 0 XFail, 0 Error, 0 ReRun ___________________________________________________________________

When running without parametrize:

import pytest

import logging

LOGGER = logging.getLogger(__name__)


@pytest.fixture(scope="module")
def fix1():
    LOGGER.info("++++++++++++++++++++++++++fix1")
    yield
    LOGGER.info("t1")


@pytest.fixture(scope="module")
def fix2():
    LOGGER.info("++++++++++++++++++++++++++fix2")
    yield
    LOGGER.info("t2")


# @pytest.mark.parametrize("fix1, fix2",
#     [
#     pytest.param(1, 2)
#     ],
#     indirect=True)
def test1(fix1, fix2):
    LOGGER.info("in test")


def test2(fix1, fix2):
    LOGGER.info("in test")

Result:

tests.test_ruty 2021-11-08 20:37:23 INFO ++++++++++++++++++++++++++fix1
tests.test_ruty 2021-11-08 20:37:23 INFO ++++++++++++++++++++++++++fix2
------------------------------------------------------------------------------------------------------ CALL ------------------------------------------------------------------------------------------------------
tests.test_ruty 2021-11-08 20:37:23 INFO in test

TEST: test1 STATUS: PASSED
.---------------------------------------------------------------------------------------------------- TEARDOWN ----------------------------------------------------------------------------------------------------

__________________________________________________________________ 1 of 2 completed, 1 Pass, 0 Fail, 0 Skip, 0 XPass, 0 XFail, 0 Error, 0 ReRun ___________________________________________________________________

tests/test_ruty.py 
------------------------------------------------------------------------------------------------------ test2 ------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------ SETUP ------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------ CALL ------------------------------------------------------------------------------------------------------
tests.test_ruty 2021-11-08 20:37:23 INFO in test

TEST: test2 STATUS: PASSED
.---------------------------------------------------------------------------------------------------- TEARDOWN ----------------------------------------------------------------------------------------------------
tests.test_ruty 2021-11-08 20:37:23 INFO t2
tests.test_ruty 2021-11-08 20:37:23 INFO t1

__________________________________________________________________ 2 of 2 completed, 2 Pass, 0 Fail, 0 Skip, 0 XPass, 0 XFail, 0 Error, 0 ReRun ___________________________________________________________________

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the parametrized and non-parametrized fixture examples from the issue and comparing their setup and teardown ordering. Trace pytest's module-scoped fixture handling during pytest_runtest_setup and pytest_runtest_teardown. Done means the parametrized case follows the requested fixture teardown flow, with regression coverage for both examples.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.