diff --git a/AUTHORS b/AUTHORS index 826556f146..ef36a4251b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -225,6 +225,7 @@ Joseph Hunkeler Joseph Sawaya Josh Karpel Joshua Bronson +Julian Valentin Jurko Gospodnetić Justice Ndou Justyna Janczyszyn diff --git a/changelog/12938.bugfix.rst b/changelog/12938.bugfix.rst new file mode 100644 index 0000000000..d54d73bdbf --- /dev/null +++ b/changelog/12938.bugfix.rst @@ -0,0 +1 @@ +Fixed ``--durations-min`` argument not respected if ``-vv`` is used. diff --git a/src/_pytest/runner.py b/src/_pytest/runner.py index d2b7fda8c2..f054328926 100644 --- a/src/_pytest/runner.py +++ b/src/_pytest/runner.py @@ -61,10 +61,10 @@ def pytest_addoption(parser: Parser) -> None: "--durations-min", action="store", type=float, - default=0.005, + default=None, metavar="N", help="Minimal duration in seconds for inclusion in slowest list. " - "Default: 0.005.", + "Default: 0.005 (or 0.0 if -vv is given).", ) @@ -74,6 +74,8 @@ def pytest_terminal_summary(terminalreporter: TerminalReporter) -> None: verbose = terminalreporter.config.get_verbosity() if durations is None: return + if durations_min is None: + durations_min = 0.005 if verbose < 2 else 0.0 tr = terminalreporter dlist = [] for replist in tr.stats.values(): @@ -90,11 +92,13 @@ def pytest_terminal_summary(terminalreporter: TerminalReporter) -> None: dlist = dlist[:durations] for i, rep in enumerate(dlist): - if verbose < 2 and rep.duration < durations_min: + if rep.duration < durations_min: tr.write_line("") - tr.write_line( - f"({len(dlist) - i} durations < {durations_min:g}s hidden. Use -vv to show these durations.)" - ) + message = f"({len(dlist) - i} durations < {durations_min:g}s hidden." + if terminalreporter.config.option.durations_min is None: + message += " Use -vv to show these durations." + message += ")" + tr.write_line(message) break tr.write_line(f"{rep.duration:02.2f}s {rep.when:<8} {rep.nodeid}") diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index ba1f86f02d..ffd1dcce21 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -1,6 +1,7 @@ # mypy: allow-untyped-defs from __future__ import annotations +from collections.abc import Sequence import dataclasses import importlib.metadata import os @@ -970,28 +971,43 @@ def test_calls_showall(self, pytester: Pytester, mock_timing) -> None: pytester.makepyfile(self.source) result = pytester.runpytest_inprocess("--durations=0") assert result.ret == 0 - - tested = "3" - for x in tested: - for y in ("call",): # 'setup', 'call', 'teardown': - for line in result.stdout.lines: - if (f"test_{x}") in line and y in line: - break - else: - raise AssertionError(f"not found {x} {y}") + TestDurations.check_tests_in_output(result.stdout.lines, 2, 3) def test_calls_showall_verbose(self, pytester: Pytester, mock_timing) -> None: pytester.makepyfile(self.source) result = pytester.runpytest_inprocess("--durations=0", "-vv") assert result.ret == 0 + TestDurations.check_tests_in_output(result.stdout.lines, 1, 2, 3) + + def test_calls_showall_durationsmin(self, pytester: Pytester, mock_timing) -> None: + pytester.makepyfile(self.source) + result = pytester.runpytest_inprocess("--durations=0", "--durations-min=0.015") + assert result.ret == 0 + TestDurations.check_tests_in_output(result.stdout.lines, 3) + + def test_calls_showall_durationsmin_verbose( + self, pytester: Pytester, mock_timing + ) -> None: + pytester.makepyfile(self.source) + result = pytester.runpytest_inprocess( + "--durations=0", "--durations-min=0.015", "-vv" + ) + assert result.ret == 0 + TestDurations.check_tests_in_output(result.stdout.lines, 3) - for x in "123": - for y in ("call",): # 'setup', 'call', 'teardown': - for line in result.stdout.lines: - if (f"test_{x}") in line and y in line: - break - else: - raise AssertionError(f"not found {x} {y}") + @staticmethod + def check_tests_in_output( + lines: Sequence[str], *expected_test_numbers: int, number_of_tests: int = 3 + ) -> None: + found_test_numbers = set( + test_number + for test_number in range(1, number_of_tests + 1) + if any( + line.endswith(f"test_{test_number}") and " call " in line + for line in lines + ) + ) + assert found_test_numbers == set(expected_test_numbers) def test_with_deselected(self, pytester: Pytester, mock_timing) -> None: pytester.makepyfile(self.source)