From 717647086659674046e3dd94a570422f69ddccc4 Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Mon, 18 Dec 2023 11:28:24 -0500 Subject: [PATCH] Correctly report teardown fixture errors --- AUTHORS | 1 + changelog/11706.bugfix.rst | 1 + src/_pytest/runner.py | 3 +++ testing/test_runner.py | 22 ++++++++++++++++++++++ 4 files changed, 27 insertions(+) create mode 100644 changelog/11706.bugfix.rst diff --git a/AUTHORS b/AUTHORS index 14a35c3d5..67e794527 100644 --- a/AUTHORS +++ b/AUTHORS @@ -54,6 +54,7 @@ Aviral Verma Aviv Palivoda Babak Keyvani Barney Gale +Ben Brown Ben Gartner Ben Webb Benjamin Peterson diff --git a/changelog/11706.bugfix.rst b/changelog/11706.bugfix.rst new file mode 100644 index 000000000..75970577c --- /dev/null +++ b/changelog/11706.bugfix.rst @@ -0,0 +1 @@ +Fix reporting of teardown errors in session and module scoped fixtures when `--maxfail=1`. diff --git a/src/_pytest/runner.py b/src/_pytest/runner.py index e20338520..6dd8e6c40 100644 --- a/src/_pytest/runner.py +++ b/src/_pytest/runner.py @@ -179,6 +179,9 @@ def pytest_runtest_call(item: Item) -> None: def pytest_runtest_teardown(item: Item, nextitem: Optional[Item]) -> None: _update_current_test_var(item, "teardown") + # If the session is about to fail, teardown everything - this is necessary + # to correctly report fixture teardown errors (see #11706) + nextitem = None if item.session.shouldfail else nextitem item.session._setupstate.teardown_exact(nextitem) _update_current_test_var(item, None) diff --git a/testing/test_runner.py b/testing/test_runner.py index c8b646857..d04822a3a 100644 --- a/testing/test_runner.py +++ b/testing/test_runner.py @@ -1087,3 +1087,25 @@ def test_outcome_exception_bad_msg() -> None: with pytest.raises(TypeError) as excinfo: OutcomeException(func) # type: ignore assert str(excinfo.value) == expected + + +def test_teardown_session_failed(pytester: Pytester) -> None: + """Test that fixture teardown failures are reported after a test fails.""" + pytester.makepyfile( + """ + import pytest + + @pytest.fixture(scope="module") + def baz(): + yield + pytest.fail("This is a failing fixture") + + def test_foo(baz): + pytest.fail("This is a failing test") + + def test_bar(baz): + pass + """ + ) + result = pytester.runpytest("--maxfail=1") + result.stdout.fnmatch_lines(["*1 failed, 1 error*"])