Show reason for skipped test in verbose mode
This commit is contained in:
parent
810b878ef8
commit
612f157dbd
|
@ -0,0 +1 @@
|
|||
Verbose mode now shows the reason that a test was skipped in the test's terminal line after the "SKIPPED", "XFAIL" or "XPASS".
|
|
@ -13,6 +13,7 @@ from functools import partial
|
|||
from pathlib import Path
|
||||
from typing import Any
|
||||
from typing import Callable
|
||||
from typing import cast
|
||||
from typing import Dict
|
||||
from typing import Generator
|
||||
from typing import List
|
||||
|
@ -545,6 +546,16 @@ class TerminalReporter:
|
|||
line = self._locationline(rep.nodeid, *rep.location)
|
||||
if not running_xdist:
|
||||
self.write_ensure_prefix(line, word, **markup)
|
||||
if rep.skipped or hasattr(report, "wasxfail"):
|
||||
available_width = (
|
||||
(self._tw.fullwidth - self._tw.width_of_current_line)
|
||||
- len(" [100%]")
|
||||
- 1
|
||||
)
|
||||
reason = _get_raw_skip_reason(rep)
|
||||
reason_ = _format_trimmed(" ({})", reason, available_width)
|
||||
if reason_ is not None:
|
||||
self._tw.write(reason_)
|
||||
if self._show_progress_info:
|
||||
self._write_progress_information_filling_space()
|
||||
else:
|
||||
|
@ -1249,6 +1260,31 @@ def _get_pos(config: Config, rep: BaseReport):
|
|||
return nodeid
|
||||
|
||||
|
||||
def _format_trimmed(format: str, msg: str, available_width: int) -> Optional[str]:
|
||||
"""Format msg into format, ellipsizing it if doesn't fit in available_width.
|
||||
|
||||
Returns None if even the ellipsis can't fit.
|
||||
"""
|
||||
# Only use the first line.
|
||||
i = msg.find("\n")
|
||||
if i != -1:
|
||||
msg = msg[:i]
|
||||
|
||||
ellipsis = "..."
|
||||
format_width = wcswidth(format.format(""))
|
||||
if format_width + len(ellipsis) > available_width:
|
||||
return None
|
||||
|
||||
if format_width + wcswidth(msg) > available_width:
|
||||
available_width -= len(ellipsis)
|
||||
msg = msg[:available_width]
|
||||
while format_width + wcswidth(msg) > available_width:
|
||||
msg = msg[:-1]
|
||||
msg += ellipsis
|
||||
|
||||
return format.format(msg)
|
||||
|
||||
|
||||
def _get_line_with_reprcrash_message(
|
||||
config: Config, rep: BaseReport, termwidth: int
|
||||
) -> str:
|
||||
|
@ -1257,11 +1293,7 @@ def _get_line_with_reprcrash_message(
|
|||
pos = _get_pos(config, rep)
|
||||
|
||||
line = f"{verbose_word} {pos}"
|
||||
len_line = wcswidth(line)
|
||||
ellipsis, len_ellipsis = "...", 3
|
||||
if len_line > termwidth - len_ellipsis:
|
||||
# No space for an additional message.
|
||||
return line
|
||||
line_width = wcswidth(line)
|
||||
|
||||
try:
|
||||
# Type ignored intentionally -- possible AttributeError expected.
|
||||
|
@ -1269,22 +1301,11 @@ def _get_line_with_reprcrash_message(
|
|||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
# Only use the first line.
|
||||
i = msg.find("\n")
|
||||
if i != -1:
|
||||
msg = msg[:i]
|
||||
len_msg = wcswidth(msg)
|
||||
available_width = termwidth - line_width
|
||||
msg = _format_trimmed(" - {}", msg, available_width)
|
||||
if msg is not None:
|
||||
line += msg
|
||||
|
||||
sep, len_sep = " - ", 3
|
||||
max_len_msg = termwidth - len_line - len_sep
|
||||
if max_len_msg >= len_ellipsis:
|
||||
if len_msg > max_len_msg:
|
||||
max_len_msg -= len_ellipsis
|
||||
msg = msg[:max_len_msg]
|
||||
while wcswidth(msg) > max_len_msg:
|
||||
msg = msg[:-1]
|
||||
msg += ellipsis
|
||||
line += sep + msg
|
||||
return line
|
||||
|
||||
|
||||
|
@ -1361,3 +1382,22 @@ def format_session_duration(seconds: float) -> str:
|
|||
else:
|
||||
dt = datetime.timedelta(seconds=int(seconds))
|
||||
return f"{seconds:.2f}s ({dt})"
|
||||
|
||||
|
||||
def _get_raw_skip_reason(report: TestReport) -> str:
|
||||
"""Get the reason string of a skip/xfail/xpass test report.
|
||||
|
||||
The string is just the part given by the user.
|
||||
"""
|
||||
if hasattr(report, "wasxfail"):
|
||||
reason = cast(str, report.wasxfail)
|
||||
if reason.startswith("reason: "):
|
||||
reason = reason[len("reason: ") :]
|
||||
return reason
|
||||
else:
|
||||
assert report.skipped
|
||||
assert isinstance(report.longrepr, tuple)
|
||||
_, _, reason = report.longrepr
|
||||
if reason.startswith("Skipped: "):
|
||||
reason = reason[len("Skipped: ") :]
|
||||
return reason
|
||||
|
|
|
@ -5,6 +5,7 @@ import sys
|
|||
import textwrap
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from typing import cast
|
||||
from typing import Dict
|
||||
from typing import List
|
||||
|
@ -23,8 +24,11 @@ from _pytest.monkeypatch import MonkeyPatch
|
|||
from _pytest.pytester import Pytester
|
||||
from _pytest.reports import BaseReport
|
||||
from _pytest.reports import CollectReport
|
||||
from _pytest.reports import TestReport
|
||||
from _pytest.terminal import _folded_skips
|
||||
from _pytest.terminal import _format_trimmed
|
||||
from _pytest.terminal import _get_line_with_reprcrash_message
|
||||
from _pytest.terminal import _get_raw_skip_reason
|
||||
from _pytest.terminal import _plugin_nameversions
|
||||
from _pytest.terminal import getreportopt
|
||||
from _pytest.terminal import TerminalReporter
|
||||
|
@ -342,6 +346,33 @@ class TestTerminal:
|
|||
color_mapping.format_for_fnmatch(["*{red}FOO{reset}*"])
|
||||
)
|
||||
|
||||
def test_verbose_skip_reason(self, pytester: Pytester) -> None:
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
import pytest
|
||||
|
||||
@pytest.mark.skip(reason="123")
|
||||
def test_1():
|
||||
pass
|
||||
|
||||
@pytest.mark.xfail(reason="456")
|
||||
def test_2():
|
||||
pass
|
||||
|
||||
@pytest.mark.xfail(reason="789")
|
||||
def test_3():
|
||||
assert False
|
||||
"""
|
||||
)
|
||||
result = pytester.runpytest("-v")
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"test_verbose_skip_reason.py::test_1 SKIPPED (123) *",
|
||||
"test_verbose_skip_reason.py::test_2 XPASS (456) *",
|
||||
"test_verbose_skip_reason.py::test_3 XFAIL (789) *",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class TestCollectonly:
|
||||
def test_collectonly_basic(self, pytester: Pytester) -> None:
|
||||
|
@ -2345,3 +2376,27 @@ class TestCodeHighlight:
|
|||
]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_raw_skip_reason_skipped() -> None:
|
||||
report = SimpleNamespace()
|
||||
report.skipped = True
|
||||
report.longrepr = ("xyz", 3, "Skipped: Just so")
|
||||
|
||||
reason = _get_raw_skip_reason(cast(TestReport, report))
|
||||
assert reason == "Just so"
|
||||
|
||||
|
||||
def test_raw_skip_reason_xfail() -> None:
|
||||
report = SimpleNamespace()
|
||||
report.wasxfail = "reason: To everything there is a season"
|
||||
|
||||
reason = _get_raw_skip_reason(cast(TestReport, report))
|
||||
assert reason == "To everything there is a season"
|
||||
|
||||
|
||||
def test_format_trimmed() -> None:
|
||||
msg = "unconditional skip"
|
||||
|
||||
assert _format_trimmed(" ({}) ", msg, len(msg) + 4) == " (unconditional skip) "
|
||||
assert _format_trimmed(" ({}) ", msg, len(msg) + 3) == " (unconditional ...) "
|
||||
|
|
Loading…
Reference in New Issue