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
Ich bin nicht sicher, wofür ich es verwenden soll, aber wenn Sie eine Funktion wie diese haben, möchte ich ihr außergewöhnliches Verhalten testen. Wenn beispielsweise "retry_interval" 0 ist, wird "time.sleep ()" nicht aufgerufen.
Es ist jedoch problematisch, DI open ()
und time.sleep ()
. Die Schnittstelle wird schmutzig. Ich möchte auch ** kwargs
vermeiden.
Also wurde mir auf Twitter "unittest.mock.patch" gesagt.
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()
Dekorateure sind einfacher.
$ python -m unittest
....
----------------------------------------------------------------------
Ran 4 tests in 0.005s
OK
Ich habe das Gefühl, dass ich es implementiert habe. Es sieht so aus, als würde es wie erwartet funktionieren. Ist es richtig, wie man es benutzt?