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
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ Simon Holesch
Simon Kerr
Skylar Downes
Srinivas Reddy Thatiparthy
Stamatis-Christos Saridakis
Stefaan Lippens
Stefan Farmbauer
Stefan Scherfke
Expand Down
2 changes: 2 additions & 0 deletions changelog/13169.improvement.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
When using ``--setup-show`` or ``--setup-only``, show a ``SETUP START``
line before each fixture starts executing, so a stalled fixture setup can be identified.
11 changes: 9 additions & 2 deletions src/_pytest/setuponly.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ def pytest_addoption(parser: Parser) -> None:
def pytest_fixture_setup(
fixturedef: FixtureDef[object], request: SubRequest
) -> Generator[None, object, object]:
if request.config.option.setupshow:
# Report this fixture before entering user code, including if it hangs.
_show_fixture_action(fixturedef, request.config, "SETUP START", end_line=True)
try:
return (yield)
finally:
Expand Down Expand Up @@ -62,7 +65,7 @@ def pytest_fixture_post_finalizer(


def _show_fixture_action(
fixturedef: FixtureDef[object], config: Config, msg: str
fixturedef: FixtureDef[object], config: Config, msg: str, *, end_line: bool = False
) -> None:
capman = config.pluginmanager.getplugin("capturemanager")
if capman:
Expand All @@ -85,7 +88,11 @@ def _show_fixture_action(
if hasattr(fixturedef, "cached_param"):
tw.write(f"[{saferepr(fixturedef.cached_param, maxsize=42)}]")

tw.flush()
# End the early marker before any output from the fixture body.
if end_line:
tw.line()
else:
tw.flush()

if capman:
capman.resume_global_capture()
Expand Down
4 changes: 4 additions & 0 deletions testing/python/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -4626,10 +4626,14 @@ def test_second(my_fixture):
result.stdout.fnmatch_lines(
[
"test_fixtures.py::test_first ",
" SETUP START F my_fixture",
"",
" SETUP F my_fixture",
" test_fixtures.py::test_first (fixtures used: my_fixture, request) PASSED",
"test_fixtures.py::test_first ERROR",
"test_fixtures.py::test_second ",
" SETUP START F my_fixture",
"",
" SETUP F my_fixture",
" test_fixtures.py::test_second (fixtures used: my_fixture, request) PASSED",
" TEARDOWN F my_fixture",
Expand Down
69 changes: 69 additions & 0 deletions testing/test_setuponly.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,75 @@
import pytest


@pytest.mark.parametrize("mode", ["--setup-show", "--setup-only"])
def test_setup_show_announces_fixture_before_body(
pytester: Pytester, mode: str
) -> None:
p = pytester.makepyfile(
"""
import pytest

@pytest.fixture(params=["example"], ids=["sample"])
def slow():
print("BODY-ENTERED", flush=True)
yield "value"

def test_value(slow):
assert slow == "value"
"""
)

result = pytester.runpytest(mode, "-s", p)
assert result.ret == 0
output = result.stdout.str()
assert "SETUP START F slow" in output
assert "SETUP F slow['sample']" in output
assert "TEARDOWN F slow['sample']" in output
assert output.index("SETUP START F slow") < output.index("BODY-ENTERED")
assert output.index("BODY-ENTERED") < output.index("SETUP F slow")
assert "SETUP START F slow\n" in output


def test_setup_show_announces_failed_fixture(pytester: Pytester) -> None:
p = pytester.makepyfile(
"""
import pytest

@pytest.fixture
def broken():
raise ValueError("fixture setup failed")

def test_failure(broken):
pass
"""
)

result = pytester.runpytest("--setup-show", p)
assert result.ret == 1
output = result.stdout.str()
assert "SETUP START F broken" in output
assert "SETUP F broken" in output
assert output.index("SETUP START F broken") < output.index("SETUP F broken")


def test_no_setup_start_when_not_requested(pytester: Pytester) -> None:
p = pytester.makepyfile(
"""
import pytest

@pytest.fixture
def normal():
return 1

def test_normal(normal):
assert normal == 1
"""
)
result = pytester.runpytest(p)
assert result.ret == 0
assert "SETUP START" not in result.stdout.str()


@pytest.fixture(params=["--setup-only", "--setup-plan", "--setup-show"], scope="module")
def mode(request):
return request.param
Expand Down
Loading