From 007d24a6faaa4e3eb8f4a7bc981093c2d7ce631a Mon Sep 17 00:00:00 2001
From: jakkdl
Date: Sun, 3 Mar 2024 13:22:23 +0100
Subject: [PATCH] improve comment getfixturevalue, move
test_scoped_fixture_teardown_order to testing/python/fixtures.py
---
src/_pytest/fixtures.py | 7 ++-
testing/python/fixtures.py | 54 +++++++++++++++++++
.../test_scope_fixture_teardown_order.py | 36 -------------
3 files changed, 59 insertions(+), 38 deletions(-)
delete mode 100644 testing/python/test_scope_fixture_teardown_order.py
diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py
index 532330fa0..fa727513c 100644
--- a/src/_pytest/fixtures.py
+++ b/src/_pytest/fixtures.py
@@ -531,8 +531,11 @@ class FixtureRequest(abc.ABC):
:raises pytest.FixtureLookupError:
If the given fixture could not be found.
"""
- # Note: This is called during setup for evaluating fixtures defined via
- # function arguments as well.
+ # Note that in addition to the use case described in the docstring,
+ # getfixturevalue() is also called by pytest itself during item setup to
+ # evaluate the fixtures that are requested statically
+ # (using function parameters, autouse, etc).
+
fixturedef = self._get_active_fixturedef(argname)
assert fixturedef.cached_result is not None, (
f'The fixture value for "{argname}" is not available. '
diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py
index 1b7a0e414..0758b590c 100644
--- a/testing/python/fixtures.py
+++ b/testing/python/fixtures.py
@@ -4561,6 +4561,60 @@ def test_deduplicate_names() -> None:
assert items == ("a", "b", "c", "d", "g", "f", "e")
+def test_scoped_fixture_teardown_order(pytester: Pytester) -> None:
+ """
+ Make sure teardowns happen in reverse order of setup with scoped fixtures, when
+ a later test only depends on a subset of scoped fixtures.
+ Regression test for https://github.com/pytest-dev/pytest/issues/1489
+ """
+ pytester.makepyfile(
+ """
+ from typing import Generator
+
+ import pytest
+
+
+ last_executed = ""
+
+
+ @pytest.fixture(scope="module")
+ def fixture_1() -> Generator[None, None, None]:
+ global last_executed
+ assert last_executed == ""
+ last_executed = "autouse_setup"
+ yield
+ assert last_executed == "noautouse_teardown"
+ last_executed = "autouse_teardown"
+
+
+ @pytest.fixture(scope="module")
+ def fixture_2() -> Generator[None, None, None]:
+ global last_executed
+ assert last_executed == "autouse_setup"
+ last_executed = "noautouse_setup"
+ yield
+ assert last_executed == "run_test"
+ last_executed = "noautouse_teardown"
+
+
+ def test_autouse_fixture_teardown_order(fixture_1: None, fixture_2: None) -> None:
+ global last_executed
+ assert last_executed == "noautouse_setup"
+ last_executed = "run_test"
+
+
+ def test_2(fixture_1: None) -> None:
+ # this would previously queue an additional teardown of fixture_1,
+ # despite fixture_1's value being cached, which caused fixture_1 to be
+ # torn down before fixture_2 - violating the rule that teardowns should
+ # happen in reverse order of setup.
+ pass
+ """
+ )
+ result = pytester.runpytest()
+ assert result.ret == 0
+
+
def test_scope_fixture_caching_1(pytester: Pytester) -> None:
"""
Make sure setup and finalization is only run once when using fixture
diff --git a/testing/python/test_scope_fixture_teardown_order.py b/testing/python/test_scope_fixture_teardown_order.py
deleted file mode 100644
index 8ce97cd32..000000000
--- a/testing/python/test_scope_fixture_teardown_order.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from typing import Generator
-
-import pytest
-
-
-last_executed = ""
-
-
-@pytest.fixture(scope="module")
-def fixture_1() -> Generator[None, None, None]:
- global last_executed
- assert last_executed == ""
- last_executed = "autouse_setup"
- yield
- assert last_executed == "noautouse_teardown"
- last_executed = "autouse_teardown"
-
-
-@pytest.fixture(scope="module")
-def fixture_2() -> Generator[None, None, None]:
- global last_executed
- assert last_executed == "autouse_setup"
- last_executed = "noautouse_setup"
- yield
- assert last_executed == "run_test"
- last_executed = "noautouse_teardown"
-
-
-def test_autouse_fixture_teardown_order(fixture_1: None, fixture_2: None) -> None:
- global last_executed
- assert last_executed == "noautouse_setup"
- last_executed = "run_test"
-
-
-def test_2(fixture_1: None) -> None:
- pass