|
| 1 | +from typing import Dict, Tuple |
| 2 | + |
| 3 | +import pytest |
| 4 | + |
| 5 | +# store history of failures per test class name and per index |
| 6 | +# in parametrize (if parametrize used) |
| 7 | +_test_failed_incremental: Dict[str, Dict[Tuple[int, ...], str]] = {} |
| 8 | + |
| 9 | + |
| 10 | +def pytest_runtest_makereport(item, call): |
| 11 | + if "incremental" in item.keywords: |
| 12 | + # incremental marker is used |
| 13 | + if call.excinfo is not None: |
| 14 | + # the test has failed |
| 15 | + # retrieve the class name of the test |
| 16 | + cls_name = str(item.cls) |
| 17 | + # retrieve the index of the test (if parametrize is used |
| 18 | + # in combination with incremental) |
| 19 | + parametrize_index = ( |
| 20 | + tuple(item.callspec.indices.values()) |
| 21 | + if hasattr(item, "callspec") |
| 22 | + else () |
| 23 | + ) |
| 24 | + # retrieve the name of the test function |
| 25 | + test_name = item.originalname or item.name |
| 26 | + # store in _test_failed_incremental the original name of the failed test |
| 27 | + _test_failed_incremental.setdefault(cls_name, {}).setdefault( |
| 28 | + parametrize_index, test_name |
| 29 | + ) |
| 30 | + |
| 31 | + |
| 32 | +def pytest_runtest_setup(item): |
| 33 | + if "incremental" in item.keywords: |
| 34 | + # retrieve the class name of the test |
| 35 | + cls_name = str(item.cls) |
| 36 | + # check if a previous test has failed for this class |
| 37 | + if cls_name in _test_failed_incremental: |
| 38 | + # retrieve the index of the test (if parametrize is used |
| 39 | + # in combination with incremental) |
| 40 | + parametrize_index = ( |
| 41 | + tuple(item.callspec.indices.values()) |
| 42 | + if hasattr(item, "callspec") |
| 43 | + else () |
| 44 | + ) |
| 45 | + # retrieve the name of the first test function to |
| 46 | + # fail for this class name and index |
| 47 | + test_name = _test_failed_incremental[cls_name].get(parametrize_index, None) |
| 48 | + # if name found, test has failed for the combination of |
| 49 | + # class name & test name |
| 50 | + if test_name is not None: |
| 51 | + pytest.xfail(f"previous test failed ({test_name})") |
0 commit comments