Python: issue with building mock function
Question: I'm writing unit tests to validate my project functionalities. I need to
replace some of the functions with mock function and I thought to use the
Python mock library. The implementation I used doesn't seem to work properly
though and I don't understand where I'm doing wrong. Here a simplified
scenario:

_root/connector.py_

    
    
    from ftp_utils.py import *
    
    def main():
        config = yaml.safe_load("vendor_sftp.yaml")
        downloaded_files = []
    
        downloaded_files = get_files(config)
        for f in downloaded_files:
          #do something
    

_root/utils/ftp_utils.py_

    
    
    import os
    import sys
    import pysftp
    
    def get_files(config):
       sftp = pysftp.Connection(config['host'], username=config['username'])
       sftp.chdir(config['remote_dir'])
       down_files = sftp.listdir()
       if down_files is not None:
         for f in down_files:
           sftp.get(f, os.path.join(config['local_dir'], f), preserve_mtime=True)
    
       return down_files
    

_root/tests/connector_tester.py_

    
    
    import unittest
    import mock
    import ftp_utils
    import connector
    
    def get_mock_files():
      return ['digital_spend.csv', 'tv_spend.csv']
    
    class ConnectorTester(unittest.TestCase)
      @mock.patch('ftp_utils.get_files', side_effect=get_mock_files)
      def test_main_process(self, get_mock_files_function):
        # I want to use a mock version of the get_files function
        connector.main() 
    

When I debug my test I expect that the get_files function called inside the
main of connector.py is the get_mock_files(), but instead is the
ftp_utils.get_files(). What am I doing wrong here? What should I change in my
code to properly call the get_mock_file() mock?

Thanks, Alessio


Answer: I think there are several problems with your scenario:

  * `connector.py` cannot import from `ftp_utils.py` that way
  * nor can `connector_tester.py`
  * as a habit, it is better to have your testing files under the form `test_xxx.py`
  * to use `unittest` with patching, see [this example](http://www.voidspace.org.uk/python/mock/patch.html#patch-methods-start-and-stop)

In general, try to provide working minimal examples so that it is easier for
everyone to run your code.

I modified rather heavily your example to make it work, but basically, the
problem is that you patch `'ftp_utils.get_files'` while it is not the
reference that is actually called inside `connector.main()` but probably
rather `'connector.get_files'`.

Here is the modified example's directory:

    
    
    test_connector.py
    ftp_utils.py
    connector.py
    

test_connector.py:

    
    
    import unittest
    import sys
    import mock
    import connector
    
    def get_mock_files(*args, **kwargs):
       return ['digital_spend.csv', 'tv_spend.csv']
    
    class ConnectorTester(unittest.TestCase):
       def setUp(self):
          self.patcher = mock.patch('connector.get_files', side_effect=get_mock_files)
          self.patcher.start()
    
       def test_main_process(self):
          # I want to use a mock version of the get_files function
          connector.main()
    
    suite = unittest.TestLoader().loadTestsFromTestCase(ConnectorTester)
    
    if __name__ == "__main__":
       unittest.main()
    

**NB:** what is called when running `connector.main()` is
`'connector.get_files'`

connector.py:

    
    
    from ftp_utils import *
    
    def main():
       config = None
       downloaded_files = []
       downloaded_files = get_files(config)
       for f in downloaded_files:
          print(f)
    

connector/ftp_utils.py unchanged.

