1

In the following question the function that uses the ftplib is defined in the same file, which makes it trivial to patch ('ftplib.FTP')

Mocking ftplib.FTP for unit testing Python code

My question is: How should I proceed if, in my test, I would like to make an instance of a class (let's call it 'A') that uses the ftplib somewhere (ie: the class A has an instance of a class B and B has an FTP object which calls connect()) ?

import unittest
from mock import patch

class TestClass(unittest.TestCase):

  @patch(???)
  def test_1(self, mock_ftp_constructor):
      mock_ftp = mock_ftp_constructor.return_value
      a = A()
      self.assertTrue(mock_ftp.connect.called)


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

If I use the solution given in the other question, I find that the ftplib is called instead of the mock. How could I know the correct path of ftplib.FTP ?

Community
  • 1
  • 1

1 Answers1

2

When dealing with imports to mock a class, it matters the way how the file (where the class is) has imported the lib.

To make the patch it is necessary to know the name of the context where the lib is called. If __name__ is 'A.B', patch would be: @patch('A.B.ftplib.FTP') if B imports FTP as import ftplib. If B imports the lib as from ftplib import FTP, it would be: @patch('A.B.FTP')

  • Hi what does this `A` and `B` stand for? Can I just use `@patch('ftplib.FTP_TLS')`? I've got a question here: https://stackoverflow.com/questions/66426586/how-to-mock-ftp-connection-with-ftps-tls-version-1-2Would be appreciated if you could take a look for me, thanks – wawawa Mar 02 '21 at 15:37
  • `A` and `B` stands for packages inside the project. When you patch a path you actually patch the reference in the file. If you have a python package `A` that has a python package `B` and the code in `B` you are using the ftplib you have to mock that instead of the ftplib itself. Remember checking the builtin __name__ to know where are you standing at the moment of the call – federicoferriff Mar 03 '21 at 17:06