0
votes

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

1

1 Answers

1
votes

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

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.