Sometimes when I import a package/module in my code I use this pattern (let's call it pattern A):
"""file_module_pattern_a.py"""
import os
def get_files(path):
"""Return list of files"""
return os.listdir(path)
Other times, I use this pattern (let's call it pattern B):
"""file_module_pattern_b.py"""
from os import listdir
def get_files(path):
"""Return list of files"""
return listdir(path_variable)
Note the differente. In pattern A, I import the whole os package, while in pattern B, I only import the listdir function. Now in my unit tests, here's what I use for pattern A:
"""Unit tests for module file_module_pattern_a"""
from file_module_pattern_a import get_files
from unittest import TestCase
from mock import patch, sentinel
class StandloneTests(TestCase):
"""Test the standalone functions"""
@patch('os.listdir')
def test_get_files(self, mock_listdir):
"""Test the get_files function"""
test_result = get_files(sentinel.PATH)
mock_listdir.assert_called_once_with(sentinel.PATH)
self.assertEqual(test_result, mock_listdir.return_value)
This works great. The only problem is... if I use pattern B with this unit test, the mock_listdir never gets called. The unit test tries to use the REAL os.listdir function.
Here's the issue at hand. When I use pattern B, I'm actually adding the function to my module, not the global scope. As a result, the patch directive needs to reference my module, not os. Here's the correct unit test patch syntax:
"""Unit tests for module file_module_pattern_b"""
from file_module_pattern_b import get_files
from unittest import TestCase
from mock import patch, sentinel
class StandloneTests(TestCase):
"""Test the standalone functions"""
@patch('file_module_pattern_b.listdir')
def test_get_files(self, mock_listdir):
"""Test the get_files function"""
test_result = get_files(sentinel.PATH)
mock_listdir.assert_called_once_with(sentinel.PATH)
self.assertEqual(test_result, mock_listdir.return_value)