I have the following function which implements the exponential backoff algorithm:
class Retry():
def exponential_backoff_retry(self, function, *args, n=1):
MAX_TRIES = 8
try:
f = function(*args)
except:
if n > MAX_TRIES:
return None
n += 1
time.sleep((2 ** n) + (random.randint(0, 1000) / 1000.0))
return self.exponential_backoff_retry(function, *args, n)
else:
return f
What I'd like to do is write a unit test that confirms the behaviour, given a passed in function for example a function making an api request - that in case of an exception it retries a number of times.
Here's what I've tried so far:
@mock.patch('requests.post')
@mock.patch('utils.retry.Retry.exponential_backoff_retry', side_effect=Exception('whoops'))
def test_exponential_backoff(self, mock_retry, req_post_mock):
req_post_mock.return_value = {"status_code": 202}
with self.assertRaises(Exception):
mock_retry(req_post_mock)
self.assertEqual(req_post_mock.return_value["status_code"], 202)
self.assertEqual(mock_retry.call.count, 8)
Any advise would be appreciated.
First of all the code supplied seems to have a little bug(except the indication one). You should either change the order of function arguments like def exponential_backoff_retry(self, function,n=1, *args):
instead of def exponential_backoff_retry(self, function, *args, n=1):
or if you prefer to make na named argument in the recursive function invocation return self.exponential_backoff_retry(function, *args, n=n)
You can create a mock class to hold the function invocation counter
class MockFunctionHelperClass:
def __init__(self, failed_attempts_before_success: int) -> None:
self.failed_attempts_before_success = failed_attempts_before_success
self.attempts_counter = 0
def mock_function(self, return_value):
self.attempts_counter += 1
if self.attempts_counter <= self.failed_attempts_before_success:
raise Exception
return return_value
you can utilize the helper class in test methods as follows:
def test_success_before_max_retries():
failed_attempts_before_success = 2
expected_result = True
mock_function_helper_class = MockFunctionHelperClass(failed_attempts_before_success)
result = Retry().exponential_backoff_retry(
mock_function_helper_class.mock_function, 1, expected_result
)
assert result == expected_result
assert (
mock_function_helper_class.attempts_counter
== failed_attempts_before_success + 1
)
or
def test_failed_attempt_limit():
expected_result = True
mock_function_helper_class = MockFunctionHelperClass(3)
result = Retry().exponential_backoff_retry(
mock_function_helper_class.mock_function, 8, expected_result
)
assert result == None
assert mock_function_helper_class.attempts_counter == 2
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.