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 @@ -503,6 +503,7 @@ Warren Markham
Wei Lin
Wil Cooley
Will Riley
Willem Adnet
William Lee
Wim Glenn
Wouter van Ackooy
Expand Down
1 change: 1 addition & 0 deletions changelog/14443.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added new CLI argument ``--name-only`` to only display the name of the test when it fails, suppressing tracebacks and other detailed information.
4 changes: 4 additions & 0 deletions doc/en/reference/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3074,6 +3074,10 @@ Output and Reporting
* ``log``: show captured logging
* ``all`` (default): show all captured output

.. option:: --name-only

Only display the name of the test when it fails, suppressing tracebacks and other detailed information.

.. option:: --color=WHEN

Color terminal output:
Expand Down
26 changes: 20 additions & 6 deletions src/_pytest/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,13 @@ def pytest_addoption(parser: Parser) -> None:
help="Controls how captured stdout/stderr/log is shown on failed tests. "
"Default: all.",
)
group.addoption(
"--name-only",
action="store_true",
default=False,
dest="name_only",
help="Only display the name of the test when it fails.",
)
group.addoption(
"--fulltrace",
"--full-trace",
Expand Down Expand Up @@ -1212,14 +1219,18 @@ def summary_failures_combined(
if style == "line":
for rep in reports:
line = self._getcrashline(rep)
self._outrep_summary(rep)
if not self.config.option.name_only:
self._outrep_summary(rep)
self.write_line(line)
else:
for rep in reports:
msg = self._getfailureheadline(rep)
self.write_sep("_", msg, red=True, bold=True)
self._outrep_summary(rep)
self._handle_teardown_sections(rep.nodeid)
if self.config.option.name_only:
self._tw.line(msg, red=True, bold=True)
else:
self.write_sep("_", msg, red=True, bold=True)
self._outrep_summary(rep)
self._handle_teardown_sections(rep.nodeid)

def summary_errors(self) -> None:
if self.config.option.tbstyle != "no":
Expand All @@ -1233,8 +1244,11 @@ def summary_errors(self) -> None:
msg = "ERROR collecting " + msg
else:
msg = f"ERROR at {rep.when} of {msg}"
self.write_sep("_", msg, red=True, bold=True)
self._outrep_summary(rep)
if self.config.option.name_only:
self._tw.line(msg, red=True, bold=True)
else:
self.write_sep("_", msg, red=True, bold=True)
self._outrep_summary(rep)

def _outrep_summary(self, rep: BaseReport) -> None:
rep.toterminal(self._tw)
Expand Down
94 changes: 94 additions & 0 deletions testing/test_name_only.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
from __future__ import annotations

import pytest


class TestNameOnly:
def test_name_only_failures(self, pytester: pytest.Pytester) -> None:
pytester.makepyfile(
"""
def test_fail1():
assert False
def test_fail2():
assert False
def test_pass():
assert True
"""
)
result = pytester.runpytest("--name-only")
result.stdout.fnmatch_lines(
[
"=* FAILURES *=",
"test_fail1",
"test_fail2",
"=* short test summary info *=",
]
)

output = result.stdout.str()
failures_part = output.split("FAILURES")[1].split("short test summary info")[0]
assert "test_fail1" in failures_part
assert "test_fail2" in failures_part
assert "assert False" not in failures_part
assert "E assert False" not in failures_part

def test_name_only_errors(self, pytester: pytest.Pytester) -> None:
p = pytester.makepyfile(
test_error="""
import pytest
@pytest.fixture
def bad_fixture():
raise RuntimeError("error in fixture")
def test_error(bad_fixture):
pass
"""
)
result = pytester.runpytest(p, "--name-only")
result.stdout.fnmatch_lines(
[
"=* ERRORS *=",
"ERROR at setup of test_error",
"=* short test summary info *=",
"ERROR test_error.py::test_error - RuntimeError: error in fixture",
]
)
output = result.stdout.str()
errors_part = output.split("ERRORS")[1].split("short test summary info")[0]
assert "ERROR at setup of test_error" in errors_part
assert "RuntimeError: error in fixture" not in errors_part

def test_name_only_collection_error(self, pytester: pytest.Pytester) -> None:
pytester.makepyfile(
"""
def test_syntax():
assert
"""
)
result = pytester.runpytest("--name-only")
result.stdout.fnmatch_lines(
[
"=* ERRORS *=",
"ERROR collecting test_name_only_collection_error.py",
"=* short test summary info *=",
"ERROR test_name_only_collection_error.py",
]
)
output = result.stdout.str()
errors_part = output.split("ERRORS")[1].split("short test summary info")[0]
assert "ERROR collecting test_name_only_collection_error.py" in errors_part
assert "SyntaxError" not in errors_part

def test_name_only_with_tb_line(self, pytester: pytest.Pytester) -> None:
pytester.makepyfile(
"""
def test_fail():
assert False
"""
)
result = pytester.runpytest("--name-only", "--tb=line")
result.stdout.fnmatch_lines(
[
"=* FAILURES *=",
"*test_name_only_with_tb_line.py*: assert False",
]
)
Loading