Skip to content

Commit 9ca4411

Browse files
committed
run-last-failure: improve reporting
1 parent 1410d3d commit 9ca4411

File tree

3 files changed

+52
-24
lines changed

3 files changed

+52
-24
lines changed

changelog/5034.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve reporting with ``--lf`` and ``--ff`` (run-last-failure).

src/_pytest/cacheprovider.py

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -157,18 +157,11 @@ def __init__(self, config):
157157
self.active = any(config.getoption(key) for key in active_keys)
158158
self.lastfailed = config.cache.get("cache/lastfailed", {})
159159
self._previously_failed_count = None
160-
self._no_failures_behavior = self.config.getoption("last_failed_no_failures")
160+
self._report_status = None
161161

162162
def pytest_report_collectionfinish(self):
163163
if self.active and self.config.getoption("verbose") >= 0:
164-
if not self._previously_failed_count:
165-
return None
166-
noun = "failure" if self._previously_failed_count == 1 else "failures"
167-
suffix = " first" if self.config.getoption("failedfirst") else ""
168-
mode = "rerun previous {count} {noun}{suffix}".format(
169-
count=self._previously_failed_count, suffix=suffix, noun=noun
170-
)
171-
return "run-last-failure: %s" % mode
164+
return "run-last-failure: %s" % self._report_status
172165

173166
def pytest_runtest_logreport(self, report):
174167
if (report.when == "call" and report.passed) or report.skipped:
@@ -196,18 +189,33 @@ def pytest_collection_modifyitems(self, session, config, items):
196189
else:
197190
previously_passed.append(item)
198191
self._previously_failed_count = len(previously_failed)
192+
199193
if not previously_failed:
200-
# running a subset of all tests with recorded failures outside
201-
# of the set of tests currently executing
202-
return
203-
if self.config.getoption("lf"):
204-
items[:] = previously_failed
205-
config.hook.pytest_deselected(items=previously_passed)
194+
# Running a subset of all tests with recorded failures
195+
# only outside of it.
196+
self._report_status = "running subset without known failures"
197+
else:
198+
if self.config.getoption("lf"):
199+
items[:] = previously_failed
200+
config.hook.pytest_deselected(items=previously_passed)
201+
else: # --failedfirst
202+
items[:] = previously_failed + previously_passed
203+
204+
noun = (
205+
"failure" if self._previously_failed_count == 1 else "failures"
206+
)
207+
suffix = " first" if self.config.getoption("failedfirst") else ""
208+
self._report_status = "rerun previous {count} {noun}{suffix}".format(
209+
count=self._previously_failed_count, suffix=suffix, noun=noun
210+
)
211+
else:
212+
self._report_status = "no previously failed tests, "
213+
if self.config.getoption("last_failed_no_failures") == "none":
214+
self._report_status += "deselecting all items."
215+
config.hook.pytest_deselected(items=items)
216+
items[:] = []
206217
else:
207-
items[:] = previously_failed + previously_passed
208-
elif self._no_failures_behavior == "none":
209-
config.hook.pytest_deselected(items=items)
210-
items[:] = []
218+
self._report_status += "not deselecting items."
211219

212220
def pytest_sessionfinish(self, session):
213221
config = self.config
@@ -303,8 +311,7 @@ def pytest_addoption(parser):
303311
dest="last_failed_no_failures",
304312
choices=("all", "none"),
305313
default="all",
306-
help="change the behavior when no test failed in the last run or no "
307-
"information about the last failures was found in the cache",
314+
help="which tests to run with no previously (known) failures.",
308315
)
309316

310317

testing/test_cacheprovider.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import py
1111

1212
import pytest
13+
from _pytest.main import EXIT_NOTESTSCOLLECTED
1314

1415
pytest_plugins = ("pytester",)
1516

@@ -251,7 +252,13 @@ def test_3():
251252
result = testdir.runpytest("--lf")
252253
result.stdout.fnmatch_lines(["*2 passed*1 desel*"])
253254
result = testdir.runpytest("--lf")
254-
result.stdout.fnmatch_lines(["*1 failed*2 passed*"])
255+
result.stdout.fnmatch_lines(
256+
[
257+
"collected 3 items",
258+
"run-last-failure: no previously failed tests, not deselecting items.",
259+
"*1 failed*2 passed*",
260+
]
261+
)
255262
result = testdir.runpytest("--lf", "--cache-clear")
256263
result.stdout.fnmatch_lines(["*1 failed*2 passed*"])
257264

@@ -425,7 +432,13 @@ def test_b2():
425432
)
426433

427434
result = testdir.runpytest(test_a, "--lf")
428-
result.stdout.fnmatch_lines(["collected 2 items", "*2 passed in*"])
435+
result.stdout.fnmatch_lines(
436+
[
437+
"collected 2 items",
438+
"run-last-failure: running subset without known failures",
439+
"*2 passed in*",
440+
]
441+
)
429442

430443
result = testdir.runpytest(test_b, "--lf")
431444
result.stdout.fnmatch_lines(
@@ -721,7 +734,14 @@ def test_2():
721734
result = testdir.runpytest("--lf", "--lfnf", "all")
722735
result.stdout.fnmatch_lines(["*2 passed*"])
723736
result = testdir.runpytest("--lf", "--lfnf", "none")
724-
result.stdout.fnmatch_lines(["*2 desel*"])
737+
result.stdout.fnmatch_lines(
738+
[
739+
"collected 2 items / 2 deselected",
740+
"run-last-failure: no previously failed tests, deselecting all items.",
741+
"* 2 deselected in *",
742+
]
743+
)
744+
assert result.ret == EXIT_NOTESTSCOLLECTED
725745

726746
def test_lastfailed_no_failures_behavior_empty_cache(self, testdir):
727747
testdir.makepyfile(

0 commit comments

Comments
 (0)