Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Creating a mock or fake directory with files for unittesting

I am trying to create a unit test for the following function:

def my_function(path):
    #Search files at the given path
    for file in os.listdir(path):
        if file.endswith(".json"):
            #Search for file i'm looking for
            if file == "file_im_looking_for.json":
                #Open file
                os.chdir(path)
                json_file=json.load(open(file))
                print json_file["name"]

However I am having trouble successfully creating a fake directory with files in order for the function to work correctly and not through errors.

Below is what I have so far but it is not working for me, and I'm not sure how to incorporate "file_im_looking_for" as the file in the fake directory.

tmpfilepath = os.path.join(tempfile.gettempdir(), "tmp-testfile")
@mock.patch('my_module.os')

def test_my_function(self):

    # make the file 'exist'
    mock_path.endswith.return_value = True

    file_im_looking_for=[{
      "name": "test_json_file",
      "type": "General"
    }]

    my_module.my_function("tmpfilepath")

Any advice where I'm going wrong or other ideas to approach this problem are appreciated!

like image 804
Catherine Avatar asked May 11 '16 10:05

Catherine


People also ask

What is mocking in unit testing Python?

New in version 3.3. unittest.mock is a library for testing in Python. It allows you to replace parts of your system under test with mock objects and make assertions about how they have been used. unittest.mock provides a core Mock class removing the need to create a host of stubs throughout your test suite.


1 Answers

First of all, you forgot to pass the mocked object to test function. The right way to use mock in your test should be like this.

@mock.patch('my_module.os')
def test_my_function(self, mock_path):

Anyway, you shouldn't mock the endswith, but the listdir. The snippet below is an example and may help you.

app.py

def check_files(path):
    files = []
    for _file in os.listdir(path):
        if _file.endswith('.json'):
            files.append(_file)
    return files

test_app.py

import unittest
import mock
from app import check_files


class TestCheckFile(unittest.TestCase):

    @mock.patch('app.os.listdir')
    def test_check_file_should_succeed(self, mock_listdir):
        mock_listdir.return_value = ['a.json', 'b.json', 'c.json', 'd.txt']
        files = check_files('.')
        self.assertEqual(3, len(files))

    @mock.patch('app.os.listdir')
    def test_check_file_should_fail(self, mock_listdir):
        mock_listdir.return_value = ['a.json', 'b.json', 'c.json', 'd.txt']
        files = check_files('.')
        self.assertNotEqual(2, len(files))

if __name__ == '__main__':
    unittest.main()

Edit: Answering your question in comment, you need to mock the json.loads and the open from your app.

@mock.patch('converter.open')
@mock.patch('converter.json.loads')
@mock.patch('converter.os.listdir')
def test_check_file_load_json_should_succeed(self, mock_listdir, mock_json_loads, mock_open):
    mock_listdir.return_value = ['a.json', 'file_im_looking_for.json', 'd.txt']
    mock_json_loads.return_value = [{"name": "test_json_file", "type": "General"}]
    files = check_files('.')
    self.assertEqual(1, len(files))

But remember! If your is too broad or hard to maintain, perhaps refactoring your API should be a good idea.

like image 188
Mauro Baraldi Avatar answered Sep 18 '22 19:09

Mauro Baraldi