open_repeatedly.py
import time
def open_repeatedly(path, retries=5, retry_interval=1.0):
while True:
try:
return open(path)
except OSError:
if retries <= 0:
raise
if retry_interval > 0:
time.sleep(retry_interval)
retries -= 1
I'm not sure what to use it for, but if you have a function like this, I'd like to test its exceptional behavior. For example, if retry_interval
is 0, time.sleep ()
will not be called.
However, it is troublesome to DI ```open () and
time.sleep () . The interface gets dirty. I also want to avoid
** kwargs``.
So, I was told on Twitter `ʻunittest.mock.patch``.
test.py
import os
from tempfile import mkstemp
import unittest
from unittest.mock import call, patch, MagicMock
import open_repeatedly
class TestOpenRepeatedly(unittest.TestCase):
def test_1(self):
with patch('open_repeatedly.open') as mock:
expected_ret = MagicMock()
mock.return_value = expected_ret
path = '/path/to/test.txt'
f = open_repeatedly.open_repeatedly(path)
self.assertEqual(f, expected_ret)
mock.assert_called_with(path)
def test_2(self):
path = '/path/to/test.txt'
with patch('open_repeatedly.open') as o_mock:
o_mock.side_effect = OSError('Test')
with patch('open_repeatedly.time.sleep') as s_mock:
calls = [call(1.0)] * 5
with self.assertRaises(OSError):
open_repeatedly.open_repeatedly(path)
self.assertEqual(5, s_mock.call_count)
s_mock.assert_has_calls(calls)
self.assertEqual(6, o_mock.call_count)
o_mock.assert_called_with(path)
def test_3(self):
path = '/path/to/test.txt'
with patch('open_repeatedly.open') as o_mock:
o_mock.side_effect = OSError('Test')
with patch('open_repeatedly.time.sleep') as s_mock:
with self.assertRaises(OSError):
open_repeatedly.open_repeatedly(
path, retry_interval=0)
self.assertEqual(0, s_mock.call_count)
self.assertEqual(6, o_mock.call_count)
o_mock.assert_called_with(path)
@patch('open_repeatedly.time.sleep')
@patch('open_repeatedly.open')
def test_4(self, o_mock, s_mock):
path = '/path/to/test.txt'
o_mock.side_effect = OSError('Test')
with self.assertRaises(OSError):
open_repeatedly.open_repeatedly(
path, retries=0)
self.assertEqual(0, s_mock.call_count)
self.assertEqual(1, o_mock.call_count)
o_mock.assert_called_with(path)
if __name__ == '__main__':
unittest.main()
Decorators are easier.
$ python -m unittest
....
----------------------------------------------------------------------
Ran 4 tests in 0.005s
OK
Feeling that I implemented it It looks like it works as expected. Is it correct for how to use it?