Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog/10819.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fixed class-scoped fixtures defined in base classes not binding to the correct test instance when inherited by child test classes -- by :user:`yastcher`.

Fixes :issue:`10819` and :issue:`14011`.
4 changes: 4 additions & 0 deletions src/_pytest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -1148,6 +1148,10 @@ def resolve_fixture_function(
# request.instance so that code working with "fixturedef" behaves
# as expected.
instance = request.instance

if instance is None and fixturedef._scope is Scope.Class:
instance = getattr(request._pyfuncitem, "instance", None)

if instance is not None:
# Handle the case where fixture is defined not in a test class, but some other class
# (for example a plugin class with a fixture), see #2270.
Expand Down
70 changes: 70 additions & 0 deletions testing/test_inherit_class_fixture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from __future__ import annotations

import typing

import pytest


class ParentBase:
"""from issue #14011"""

name = ""
variable = ""

def setup(self) -> None:
self.variable = self.name

def teardown(self) -> None:
pass

@pytest.fixture(scope="class")
def fix(self) -> typing.Generator[None]:
self.setup()
yield
self.teardown()

@pytest.fixture(scope="class", autouse=True)
def base_autouse(self) -> None:
self.flag = True


@pytest.mark.usefixtures("fix")
class Test1(ParentBase):
name = "test1"

def test_a(self) -> None:
assert self.variable == self.name


@pytest.mark.usefixtures("fix")
class Test2(ParentBase):
name = "test2"

def test_a(self) -> None:
assert self.variable == self.name


class TestChild(ParentBase):
def test_flag(self) -> None:
assert self.flag


class BaseTestClass:
"""from issue #10819"""

test_func_scope_set = None
test_class_scope_set = None

@pytest.fixture(scope="class", autouse=True)
def dummy_class_fixture(self) -> None:
self.test_class_scope_set = True

@pytest.fixture(scope="function", autouse=True)
def dummy_func_fixture(self) -> None:
self.test_func_scope_set = True


class TestDummy(BaseTestClass):
def test_dummy(self) -> None:
assert self.test_func_scope_set is True
assert self.test_class_scope_set is True