Skip to content

Possible Bug in package scoped fixture teardown #4684

Description

@s0undt3ch

Please consider the following diff against PyTest 4.1:

diff --git a/testing/python/fixture.py b/testing/python/fixture.py
index b6692ac9..7b59cef0 100644
--- a/testing/python/fixture.py
+++ b/testing/python/fixture.py
@@ -3792,7 +3792,11 @@ class TestScopeOrdering(object):
             ├── sub1
             │   ├── __init__.py
             │   ├── conftest.py
-            │   └── test_1.py
+            │   ├── test_1.py
+            │   └── sub1_2
+            │       ├── __init__.py
+            │       ├── conftest.py
+            │       └── test_1_2.py
             └── sub2
                 ├── __init__.py
                 ├── conftest.py
@@ -3824,6 +3828,30 @@ class TestScopeOrdering(object):
         """
             )
         )
+        sub1_2 = sub1.mkdir("sub1_2")
+        sub1_2.ensure("__init__.py")
+        sub1_2.join("conftest.py").write(
+            textwrap.dedent(
+                """\
+            import pytest
+            from ... import values
+            @pytest.fixture(scope="package")
+            def fix():
+                values.append("pre-sub1_2")
+                yield values
+                assert values.pop() == "pre-sub1_2"
+        """
+            )
+        )
+        sub1_2.join("test_1_2.py").write(
+            textwrap.dedent(
+                """\
+            from ... import values
+            def test_1_2(fix):
+                assert values == ["pre-sub1_2"]
+        """
+            )
+        )
         sub2 = root.mkdir("sub2")
         sub2.ensure("__init__.py")
         sub2.join("conftest.py").write(
@@ -3849,7 +3877,103 @@ class TestScopeOrdering(object):
             )
         )
         reprec = testdir.inline_run()
-        reprec.assertoutcome(passed=2)
+        reprec.assertoutcome(passed=3)
+
+    def test_multiple_packages_inherit(self, testdir):
+        """Complex test involving multiple package fixtures. Make sure teardowns
+        are executed in order.
+        .
+        └── root
+            ├── __init__.py
+            ├── sub1
+            │   ├── __init__.py
+            │   ├── conftest.py
+            │   ├── test_1.py
+            │   └── sub1_2
+            │       ├── __init__.py
+            │       ├── conftest.py
+            │       └── test_1_2.py
+            └── sub2
+                ├── __init__.py
+                ├── conftest.py
+                └── test_2.py
+        """
+        root = testdir.mkdir("root")
+        root.join("__init__.py").write("values = []")
+        sub1 = root.mkdir("sub1")
+        sub1.ensure("__init__.py")
+        sub1.join("conftest.py").write(
+            textwrap.dedent(
+                """\
+            import pytest
+            from .. import values
+            @pytest.fixture(scope="package")
+            def fix():
+                values.append("pre-sub1")
+                yield values
+                assert values.pop() == "pre-sub1"
+        """
+            )
+        )
+        sub1.join("test_1.py").write(
+            textwrap.dedent(
+                """\
+            from .. import values
+            def test_1(fix):
+                assert values == ["pre-sub1"]
+        """
+            )
+        )
+        sub1_2 = sub1.mkdir("sub1_2")
+        sub1_2.ensure("__init__.py")
+        sub1_2.join("conftest.py").write(
+            textwrap.dedent(
+                """\
+            import pytest
+            from ... import values
+            @pytest.fixture(scope="package")
+            def fix(fix):
+                values.append("pre-sub1_2")
+                yield values
+                assert values.pop() == "pre-sub1_2"
+        """
+            )
+        )
+        sub1_2.join("test_1_2.py").write(
+            textwrap.dedent(
+                """\
+            from ... import values
+            def test_1_2(fix):
+                assert values == ["pre-sub1", "pre-sub1_2"]
+        """
+            )
+        )
+        sub2 = root.mkdir("sub2")
+        sub2.ensure("__init__.py")
+        sub2.join("conftest.py").write(
+            textwrap.dedent(
+                """\
+            import pytest
+            from .. import values
+            @pytest.fixture(scope="package")
+            def fix():
+                values.append("pre-sub2")
+                yield values
+                assert values.pop() == "pre-sub2"
+        """
+            )
+        )
+        sub2.join("test_2.py").write(
+            textwrap.dedent(
+                """\
+            from .. import values
+            def test_2(fix):
+                assert values == ["pre-sub2"]
+        """
+            )
+        )
+        reprec = testdir.inline_run()
+        reprec.assertoutcome(passed=3)
 
 
 def test_call_fixture_function_error():

The difference in the tests is that on test_multiple_packages, there's no fixture reuse/extend, while on test_multiple_packages_inherit I "extend" the fix fixture.

On test_multiple_packages_inherit, at teardown, I expect sub_1_2 to cleanup first, then sub_1, but the test fails at sub_2 because it still contains the item added in sub_1(which didn't ran it's teardown code yet?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: fixturesanything involving fixtures directly or indirectlytype: bugproblem that needs to be addressed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions