Question

I have a python method does the following:

  1. list the files under a directory using os.listdir(/test)
  2. regex match some of the files under the directory, put the files in a list
  3. 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 
}
Was it helpful?

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()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top