Hi,
After merging those two PRs: #205, #207, I observed some bug connected with executing session teardown in my tests. For some important reasons sometimes I need to "dynamically" skip tests in setup phase in test fixture. Last changes caused, that when this skip is performed in one fixture, then no teardown is applied in another one (with session scope). For better understanding of this problem I prepared this simple demo:
import pytest
@pytest.fixture(scope='session')
def first():
print("\n---session_setup---")
yield
print("\n---session_teardown---")
@pytest.fixture(scope='function')
def second():
pytest.skip('fixture skip')
yield
def test_a(first, second):
pass
Then when I run this test with command:
I get following and expected output (session teardown is applied correctly):
test_reruns_skip.py::test_a
---session_setup---
SKIPPED (fixture skip)
---session_teardown---
But when I run the same test with reruns in command:
I get following wrong output (session teardown is not applied):
test_reruns_skip.py::test_a
---session_setup---
SKIPPED (fixture skip)
Source of problem
After analyzing of last changes I discovered, that the problem comes from this fragment:
|
@pytest.hookimpl(hookwrapper=True) |
|
def pytest_runtest_makereport(item, call): |
|
outcome = yield |
|
result = outcome.get_result() |
|
if call.when == "call": |
|
item.test_failed = result.failed |
item.test_failed status is saved only when
call phase is executed. In my example this fragment is never reached and as a result later in
pytest_runtest_teardown function this situation is wrongly considered as this one which should be rerun due to the lack of
item.test_failed attribute:
|
# teardown when test not failed or rerun limit exceeded |
|
if item.execution_count > reruns or getattr(item, "test_failed", None) is False: |
|
item.teardown() |
|
else: |
|
# clean cashed results from any level of setups |
Suggestions for solving the problem
The simplest way for solving above problem is just setting item.test_failed attribute every time, when pytest_runtest_makereport hook is called, like this:
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
result = outcome.get_result()
item.test_failed = result.failed
But I'm not an expert in rerunfailures plugin (and pytest neither), so I don't know if it is safe solution.
More complex (but probably more safer) solution can be like this:
def pytest_runtest_teardown(item, nextitem):
...
# teardown when test not failed or rerun limit exceeded
_test_failed_statuses = getattr(item, "_test_failed_statuses", {})
if item.execution_count > reruns or not any(_test_failed_statuses.values()):
item.teardown()
else:
# clean cashed results from any level of setups
...
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
result = outcome.get_result()
if result.when == 'setup':
# clean failed statuses at the beginning of each test/rerun
setattr(item, '_test_failed_statuses', {})
_test_failed_statuses = getattr(item, '_test_failed_statuses', {})
_test_failed_statuses[result.when] = result.failed
item._test_failed_statuses = _test_failed_statuses
The problem is that both solutions cause failures in unit tests, and I have no idea how to solve my problem in better way, or how to fix those tests.
@lukasNebr @icemac could you help me with this problem or could you propose better solution?
I'm working with:
Python 3.8.5
pytest-7.2.0
rerunfailures-11.2.dev0
Hi,
After merging those two PRs: #205, #207, I observed some bug connected with executing session teardown in my tests. For some important reasons sometimes I need to "dynamically" skip tests in
setupphase in test fixture. Last changes caused, that when this skip is performed in one fixture, then no teardown is applied in another one (withsessionscope). For better understanding of this problem I prepared this simple demo:Then when I run this test with command:
I get following and expected output (session teardown is applied correctly):
But when I run the same test with reruns in command:
I get following wrong output (session teardown is not applied):
Source of problem
After analyzing of last changes I discovered, that the problem comes from this fragment:
pytest-rerunfailures/pytest_rerunfailures.py
Lines 540 to 545 in 15a3e94
item.test_failedstatus is saved only whencallphase is executed. In my example this fragment is never reached and as a result later inpytest_runtest_teardownfunction this situation is wrongly considered as this one which should be rerun due to the lack ofitem.test_failedattribute:pytest-rerunfailures/pytest_rerunfailures.py
Lines 520 to 524 in 15a3e94
Suggestions for solving the problem
The simplest way for solving above problem is just setting
item.test_failedattribute every time, whenpytest_runtest_makereporthook is called, like this:But I'm not an expert in
rerunfailuresplugin (andpytestneither), so I don't know if it is safe solution.More complex (but probably more safer) solution can be like this:
The problem is that both solutions cause failures in unit tests, and I have no idea how to solve my problem in better way, or how to fix those tests.
@lukasNebr @icemac could you help me with this problem or could you propose better solution?
I'm working with:
Python 3.8.5pytest-7.2.0rerunfailures-11.2.dev0