Reputation: 527
I would like to set os.listdir to raise OSError in UT but it not raise anything.
My code:
def get_list_of_files(path):
try:
list_of_files = sorted([filename for filename in
os.listdir(path) if
filename.startswith('FILE')])
except OSError as error:
raise Exception(error)
return list_of_files
def setUp(self):
self.listdir_patcher = patch('os.listdir')
self.mock_listdir = self.listdir_patcher.start()
self.mock_listdir_rv = MagicMock()
self.mock_listdir.return_value = self.mock_listdir_rv
def tearDown(self):
self.listdir_patcher.stop()
def test(self):
e = OSError('abc')
self.mock_listdir_rv.side_effect = e
with self.assertRaises(OSError):
get_list_of_files('path')
What is the problem? (I can not use normal Mock to os.listdir)
Upvotes: 0
Views: 351
Reputation: 1124988
You need to set the side effect for self.mock_listdir
, not it's return value:
def test(self):
e = OSError('abc')
self.mock_listdir.side_effect = e
with self.assertRaises(OSError):
get_list_of_files('path')
After all, you want the call to os.listdir()
to raise the exception, not the call to the return value of os.listdir()
(you never use os.listdir()()
).
Demo (using patch()
as a context manager, which has the same effects as using it as a decorator):
>>> from unittest.mock import patch
>>> import os
>>> with patch('os.listdir') as mock_listdir:
... mock_listdir.side_effect = OSError('abc')
... os.listdir('path')
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/unittest/mock.py", line 930, in __call__
return _mock_self._mock_call(*args, **kwargs)
File "/Users/mjpieters/Development/Library/buildout.python/parts/opt/lib/python3.6/unittest/mock.py", line 986, in _mock_call
raise effect
OSError: abc
Note that setting the side_effect
of the self.mock_listdir
mock will persist to other tests! You should really use a new patch per test. You can use patch
as a decorator on each test, use this instead of using a per-testcase patcher:
@patch('os.listdir')
def test(self, mock_listdir):
e = OSError('abc')
mock_listdir.side_effect = e
with self.assertRaises(OSError):
get_list_of_files('path')
If you do stick to using a patcher you start in the setUp
, you'd have to clear the side effect afterwards (set it to None
).
Aside from all that, there is no need to explicitly create the MagicMock
instance for a return_value
; that's the default return value already. You could instead store that default:
self.mock_listdir = self.listdir_patcher.start()
self.mock_listdir_rv = self.mock_listdir.return_value
Upvotes: 1