Skip to content
Closed
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
8 changes: 8 additions & 0 deletions src/_pytest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -1275,6 +1275,14 @@ def execute(self, request: SubRequest) -> FixtureValue:
for parent_fixture in requested_fixtures_that_should_finalize_us:
parent_fixture.addfinalizer(finalizer)

# If a previous call to execute() raised before caching the result
# (e.g. because pytest_fixture_setup turned a warning into an error),
# self._finalizers may still contain stale entries: finish() is a
# no-op when cached_result is None (it assumes "already finished"),
# so those finalizers are never drained. Clear them here so this
# fresh execution starts from a clean slate.
# See https://github.com/pytest-dev/pytest/issues/14775
self._finalizers.clear()
# Register the pytest_fixture_post_finalizer as the first finalizer,
# which is executed last.
assert not self._finalizers
Expand Down
43 changes: 43 additions & 0 deletions testing/deprecated_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,49 @@ def test_foo(self, fix):
)


def test_class_scoped_instance_method_werror_multiple_tests(
pytester: Pytester,
) -> None:
"""Multiple tests sharing a class-scoped instance-method fixture must each report
the deprecation warning (not an internal AssertionError) when -Werror is active.

Regression test for https://github.com/pytest-dev/pytest/issues/14775.
When -Werror turns the PytestRemovedIn10Warning into an error during fixture
setup, FixtureDef.execute() exited without caching the result, leaving stale
entries in self._finalizers. The second test then hit
``assert not self._finalizers`` with an internal AssertionError instead of the
expected deprecation error.
"""
pytester.makepyfile(
"""
import pytest

class TestFixt:
@pytest.fixture(scope="class")
def fixt(self):
yield

def test_1(self, fixt):
pass

def test_2(self, fixt):
pass
"""
)
result = pytester.runpytest("-Werror::pytest.PytestRemovedIn10Warning")
result.assert_outcomes(errors=2)
# Both tests should report the deprecation warning, not an AssertionError.
result.stdout.fnmatch_lines(
[
"*ERROR at setup of TestFixt.test_1*",
"*PytestRemovedIn10Warning*",
"*ERROR at setup of TestFixt.test_2*",
"*PytestRemovedIn10Warning*",
]
)
result.stdout.no_fnmatch_line("*AssertionError*")


@pytest.mark.parametrize(
"scope", [Scope.Class, Scope.Module, Scope.Package, Scope.Session]
)
Expand Down