Skip to content

Commit ff1759c

Browse files
committed
correct-class-fixtures(#10819) (#14011)
1 parent abd0154 commit ff1759c

File tree

3 files changed

+77
-0
lines changed

3 files changed

+77
-0
lines changed

changelog/10819.bugfix.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixed class-scoped fixtures defined in base classes not binding to the correct test instance when inherited by child test classes -- by :user:`yastcher`.
2+
3+
Fixes :issue:`10819` and :issue:`14011`.

src/_pytest/fixtures.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,10 @@ def resolve_fixture_function(
11481148
# request.instance so that code working with "fixturedef" behaves
11491149
# as expected.
11501150
instance = request.instance
1151+
1152+
if instance is None and fixturedef._scope is Scope.Class:
1153+
instance = getattr(request._pyfuncitem, "instance", None)
1154+
11511155
if instance is not None:
11521156
# Handle the case where fixture is defined not in a test class, but some other class
11531157
# (for example a plugin class with a fixture), see #2270.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from __future__ import annotations
2+
3+
import typing
4+
5+
import pytest
6+
7+
8+
class ParentBase:
9+
"""from issue #14011"""
10+
11+
name = ""
12+
variable = ""
13+
14+
def setup(self) -> None:
15+
self.variable = self.name
16+
17+
def teardown(self) -> None:
18+
pass
19+
20+
@pytest.fixture(scope="class")
21+
def fix(self) -> typing.Generator[None]:
22+
self.setup()
23+
yield
24+
self.teardown()
25+
26+
@pytest.fixture(scope="class", autouse=True)
27+
def base_autouse(self) -> None:
28+
self.flag = True
29+
30+
31+
@pytest.mark.usefixtures("fix")
32+
class Test1(ParentBase):
33+
name = "test1"
34+
35+
def test_a(self) -> None:
36+
assert self.variable == self.name
37+
38+
39+
@pytest.mark.usefixtures("fix")
40+
class Test2(ParentBase):
41+
name = "test2"
42+
43+
def test_a(self) -> None:
44+
assert self.variable == self.name
45+
46+
47+
class TestChild(ParentBase):
48+
def test_flag(self) -> None:
49+
assert self.flag
50+
51+
52+
class BaseTestClass:
53+
"""from issue #10819"""
54+
55+
test_func_scope_set = None
56+
test_class_scope_set = None
57+
58+
@pytest.fixture(scope="class", autouse=True)
59+
def dummy_class_fixture(self) -> None:
60+
self.test_class_scope_set = True
61+
62+
@pytest.fixture(scope="function", autouse=True)
63+
def dummy_func_fixture(self) -> None:
64+
self.test_func_scope_set = True
65+
66+
67+
class TestDummy(BaseTestClass):
68+
def test_dummy(self) -> None:
69+
assert self.test_func_scope_set is True
70+
assert self.test_class_scope_set is True

0 commit comments

Comments
 (0)