diff --git a/doc/en/example/simple.rst b/doc/en/example/simple.rst index 1570850fc50..1a5c5b444cb 100644 --- a/doc/en/example/simple.rst +++ b/doc/en/example/simple.rst @@ -461,21 +461,49 @@ an ``incremental`` marker which is to be used on classes: # content of conftest.py - import pytest + # store history of failures per test class name and per index in parametrize (if parametrize used) + _test_failed_incremental: Dict[str, Dict[Tuple[int, ...], str]] = {} def pytest_runtest_makereport(item, call): if "incremental" in item.keywords: + # incremental marker is used if call.excinfo is not None: - parent = item.parent - parent._previousfailed = item + # the test has failed + # retrieve the class name of the test + cls_name = str(item.cls) + # retrieve the index of the test (if parametrize is used in combination with incremental) + parametrize_index = ( + tuple(item.callspec.indices.values()) + if hasattr(item, "callspec") + else () + ) + # retrieve the name of the test function + test_name = item.originalname or item.name + # store in _test_failed_incremental the original name of the failed test + _test_failed_incremental.setdefault(cls_name, {}).setdefault( + parametrize_index, test_name + ) def pytest_runtest_setup(item): if "incremental" in item.keywords: - previousfailed = getattr(item.parent, "_previousfailed", None) - if previousfailed is not None: - pytest.xfail("previous test failed ({})".format(previousfailed.name)) + # retrieve the class name of the test + cls_name = str(item.cls) + # check if a previous test has failed for this class + if cls_name in _test_failed_incremental: + # retrieve the index of the test (if parametrize is used in combination with incremental) + parametrize_index = ( + tuple(item.callspec.indices.values()) + if hasattr(item, "callspec") + else () + ) + # retrieve the name of the first test function to fail for this class name and index + test_name = _test_failed_incremental[cls_name].get(parametrize_index, None) + # if name found, test has failed for the combination of class name & test name + if test_name is not None: + pytest.xfail("previous test failed ({})".format(test_name)) + These two hook implementations work together to abort incremental-marked tests in a class. Here is a test module example: