From c94722492058f2595b8e0aa1b43cf082c427af85 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 1 Nov 2019 10:12:14 +0100 Subject: [PATCH] short test summary: include lineno of crash Uses "%s:%d(%s)" % (path,) Uses `"%s:%d(%s)" % (path, testloc.lineno, testname)` for locations in tests, and `"%s (%s:%d)" % (nodeid, testloc_path, testloc.lineno)` otherwise. Fixes https://github.com/pytest-dev/pytest/issues/5241. Closes https://github.com/blueyed/pytest/pull/38. --- src/_pytest/terminal.py | 26 +++++++++++++++++++++++++- testing/test_skipping.py | 23 ++++++++++++++++------- testing/test_terminal.py | 4 ++-- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index d420d6b1011..6e5a420648d 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -9,6 +9,7 @@ import sys import time from functools import partial +from pathlib import Path from typing import Callable from typing import Dict from typing import List @@ -1007,7 +1008,30 @@ def show_skipped(lines: List[str]) -> None: def _get_pos(config, rep): nodeid = config.cwd_relative_nodeid(rep.nodeid) - return nodeid + path, _, testname = nodeid.partition("::") + if not testname: + return nodeid + + # Append location (line number). + # This uses the first traceback entry for the location in the test itself + # (rather than reprcrash, which might be less relevant for going to + # directly, e.g. pexpect failures in pytest itself). + try: + testloc = rep.longrepr.reprtraceback.reprentries[0].reprfileloc + except AttributeError: + return nodeid + + assert isinstance(testloc.path, str), testloc.path + testloc_path = Path(testloc.path) + try: + testloc_path = testloc_path.relative_to(config.invocation_dir) + except ValueError: + pass + + if str(testloc_path) == path: + return "%s:%d(%s)" % (path, testloc.lineno, testname) + + return "%s (%s:%d)" % (nodeid, testloc_path, testloc.lineno) def _get_line_with_reprcrash_message(config, rep, termwidth): diff --git a/testing/test_skipping.py b/testing/test_skipping.py index ecc6181693b..5dd2af285d5 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -257,14 +257,23 @@ def test_this_false(): assert 1 """ ) + from _pytest.runner import CallInfo + + from_call_code = CallInfo.from_call.__func__.__code__ + loc = "{}:{}".format( + from_call_code.co_filename, from_call_code.co_firstlineno + 7 + ) + result = testdir.runpytest(p, "-rx") result.stdout.fnmatch_lines( [ - "*test_one*test_this*", - "*NOTRUN*noway", - "*test_one*test_this_true*", - "*NOTRUN*condition:*True*", - "*1 passed*", + "*= short test summary info =*", + "", + "XFAIL test_one.py::test_this ({})".format(loc), + " reason: [NOTRUN] noway", + "XFAIL test_one.py::test_this_true ({})".format(loc), + " reason: [NOTRUN] condition: True", + "*= 1 passed, 2 xfailed in *", ] ) @@ -1168,8 +1177,8 @@ def test_pytest_fail(): [ "=* FAILURES *=", "*= short test summary info =*", - "FAILED test_summary_list_after_errors.py::test_fail - assert 0", - "FAILED test_summary_list_after_errors.py::test_pytest_fail - fail exc", + "FAILED test_summary_list_after_errors.py:3(test_fail) - assert 0", + "FAILED test_summary_list_after_errors.py:6(test_pytest_fail) - fail exc", ] ) diff --git a/testing/test_terminal.py b/testing/test_terminal.py index 02ac5a09356..26de8fd8263 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -775,8 +775,8 @@ def test_linematcher(): result.stdout.fnmatch_lines( [ "*test summary*", - "FAILED test_fail_extra_reporting.py::test_this - AssertionError: this_failedt...", - "FAILED test_fail_extra_reporting.py::test_linematcher - remains unmatched: 'l...", + "FAILED test_fail_extra_reporting.py:2(test_this) - AssertionError: this_faile...", + "FAILED test_fail_extra_reporting.py:7(test_linematcher) - remains unmatched: ...", "*= 2 failed in *", ] )