How to mock python build in methods
-
11-06-2021 - |
Question
I have a python method does the following:
- list the files under a directory using os.listdir(/test)
- regex match some of the files under the directory, put the files in a list
- read the contents out of files in the list, do some aggregation stuff.
Obviously, the only interesting part for me to test in my case is 2, 3, so 1 is definitely something I want to mock against. I started doing patch file creation/deletion under /test folder in my setUp() and tearDown(). But colleague told me it's not good idea to do I/O in unitest.
so what's the best way to mock build in os.listdir() in my unitest? or what's the alternatives?
Is there anything I can do to achieve something like:
setUp() {
#mock a few files eg.test1.txt, test2.txt, test3.txt under directory /test
#without physically creating them using I/O
}
tearDown() {
#whatever cleanup required
}
Solution
What about using the Mock module?
>>> import os
>>> from mock import MagicMock
>>> os.listdir = MagicMock(return_value=['file1.txt', 'file2.txt', 'file3.txt'])
>>> os.listdir('./test')
['file1.txt', 'file2.txt', 'file3.txt']
If you don't want to mokey-patch (ie. break) os, then you could use mock_os or the likes.
Read about starting and stopping:
http://docs.python.org/dev/py3k/library/unittest.mock.html#patch-methods-start-and-stop
And:
http://docs.python.org/dev/py3k/library/unittest.mock.html#quick-guide
OTHER TIPS
I find that the Mock Module is the way to go for both listing files and reading mocked data. These can of course be combined in one test but I have separated these out in a working file for clarity.
import unittest
from mock import patch, mock_open
import os
class Test(unittest.TestCase):
@patch.object(os, 'listdir')
def test_listdir(self, mock_listdir):
expected = ['file1.txt', 'file2.txt']
mock_listdir.return_value = expected
self.assertEquals(expected, Code().get_folder("~"))
def test_file_mock(self):
expected_string = "Some File Contents"
mocked_file_object = mock_open(read_data=expected_string)
with patch('__main__.open', mocked_file_object, create=True) as mocked_open:
self.assertEquals(expected_string, Code().get_file_as_string('any'))
class Code(object):
def get_folder(self, folder):
return os.listdir(folder)
def get_file_as_string(self, afile):
with open(afile, 'r') as handle:
return handle.read()
if __name__ == '__main__':
unittest.main()