Reputation: 183
Can I ask for failed tests in pytest Some number of restarts (retries). For example: if 2 attempts fail and the third succeeds, then the total result succeeds
Upvotes: 15
Views: 17978
Reputation: 8572
AFAIK, this is implemented in pytest-rerunfailures plugin. Take a look into.
e.g.
$ pip install pytest-rerunfailures
$ pytest --reruns 5
2023 update: later versions of pytest bundle relevant functionality
Upvotes: 26
Reputation: 636
Using the pytest-rerunfailures package is a good approach, but sometimes it may not be strong enough. If you need custom options, this implementation can be useful.
from pytest import fixture
from functools import wraps
import time
def retry_test(stop_max_attempt_number=5, wait_fixed=5):
def decorator(test_func_ref):
@wraps(test_func_ref)
def wrapper(*args, **kwargs):
retry_count = 1
while retry_count < stop_max_attempt_number:
try:
return test_func_ref(*args, **kwargs)
except AssertionError as assert_error:
assert_message, _ = assert_error.__str__().split("\n")
print(f"Retry error: \"{test_func_ref.__name__}\" --> {assert_message}. "
f"[{retry_count}/{stop_max_attempt_number - 1}] Retrying new execution in {wait_fixed} second(s)")
time.sleep(wait_fixed)
retry_count += 1
# Preserve original traceback in case assertion Failed
return test_func_ref(*args, **kwargs)
return wrapper
return decorator
class Test:
@fixture(scope="class")
def env(self):
return {
"retry": 10,
"sleep": 5,
"data": iter([{"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}, {"id": 10}])
}
@retry_test(stop_max_attempt_number=5, wait_fixed=2)
def test_product(self, env):
message_product = next(env["data"], None)
print(f"Reading message. {message_product}")
if message_product["id"] == 10:
assert True, "Message was intercepted"
else:
assert False, f"No message arrived"
Output
Reading message. {'id': 1}
Retry error: "test_product" --> No message arrived. [1/4] Retrying new execution in 2 second(s)
Reading message. {'id': 2}
Retry error: "test_product" --> No message arrived. [2/4] Retrying new execution in 2 second(s)
Reading message. {'id': 3}
Retry error: "test_product" --> No message arrived. [3/4] Retrying new execution in 2 second(s)
Reading message. {'id': 4}
Retry error: "test_product" --> No message arrived. [4/4] Retrying new execution in 2 second(s)
Reading message. {'id': 5}
FAILED
retry_helper.py:40 (Test.test_product)
self = <helpers.retry_helper.Test object at 0x0000021F2793EF28>
env = {'data': <list_iterator object at 0x0000021F2793EF60>, 'retry': 10, 'sleep': 5}
@retry_test(stop_max_attempt_number=5, wait_fixed=2)
def test_product(self, env):
message_product = next(env["data"], None)
print(f"Reading message. {message_product}")
if message_product["id"] == 10:
assert True, "Message was intercepted"
else:
> assert False, f"No message arrived"
E AssertionError: No message arrived
E assert False
retry_helper.py:50: AssertionError
Upvotes: 5