Skip to content

Commit d848a20

Browse files
sdementennicoddemus
authored andcommitted
Extend the incremental marker for parametrize
The incremental marker is adapted to handle properly test classes with parametrize defined at class level. Fix #3125
1 parent a9eab07 commit d848a20

File tree

1 file changed

+34
-6
lines changed

1 file changed

+34
-6
lines changed

doc/en/example/simple.rst

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -461,21 +461,49 @@ an ``incremental`` marker which is to be used on classes:
461461
462462
# content of conftest.py
463463
464-
import pytest
464+
# store history of failures per test class name and per index in parametrize (if parametrize used)
465+
_test_failed_incremental: Dict[str, Dict[Tuple[int, ...], str]] = {}
465466
466467
467468
def pytest_runtest_makereport(item, call):
468469
if "incremental" in item.keywords:
470+
# incremental marker is used
469471
if call.excinfo is not None:
470-
parent = item.parent
471-
parent._previousfailed = item
472+
# the test has failed
473+
# retrieve the class name of the test
474+
cls_name = str(item.cls)
475+
# retrieve the index of the test (if parametrize is used in combination with incremental)
476+
parametrize_index = (
477+
tuple(item.callspec.indices.values())
478+
if hasattr(item, "callspec")
479+
else ()
480+
)
481+
# retrieve the name of the test function
482+
test_name = item.originalname or item.name
483+
# store in _test_failed_incremental the original name of the failed test
484+
_test_failed_incremental.setdefault(cls_name, {}).setdefault(
485+
parametrize_index, test_name
486+
)
472487
473488
474489
def pytest_runtest_setup(item):
475490
if "incremental" in item.keywords:
476-
previousfailed = getattr(item.parent, "_previousfailed", None)
477-
if previousfailed is not None:
478-
pytest.xfail("previous test failed ({})".format(previousfailed.name))
491+
# retrieve the class name of the test
492+
cls_name = str(item.cls)
493+
# check if a previous test has failed for this class
494+
if cls_name in _test_failed_incremental:
495+
# retrieve the index of the test (if parametrize is used in combination with incremental)
496+
parametrize_index = (
497+
tuple(item.callspec.indices.values())
498+
if hasattr(item, "callspec")
499+
else ()
500+
)
501+
# retrieve the name of the first test function to fail for this class name and index
502+
test_name = _test_failed_incremental[cls_name].get(parametrize_index, None)
503+
# if name found, test has failed for the combination of class name & test name
504+
if test_name is not None:
505+
pytest.xfail("previous test failed ({})".format(test_name))
506+
479507
480508
These two hook implementations work together to abort incremental-marked
481509
tests in a class. Here is a test module example:

0 commit comments

Comments
 (0)