How to mock FTP connection with FTPS/TLS version 1.2?
Asked Answered
F

2

0

I have a Python code to read some files from FPT using FTPS and TLS version 1.2, this is the function, the credentials are read from AWS secret manager:

def ftp_connection(host, username, password):

    try:
        ftp_connection = ftplib.FTP_TLS(host, username, password)

        # set TLS version 1.2
        ftp_connection.ssl_version = ssl.PROTOCOL_TLSv1_2

        # switching to secure data connection
        ftp_connection.prot_p()

    except ftplib.all_errors as err:
        print(err)

    return ftp_connection

I wonder how I can write unit tests for this function, I'd like to test: 1.verify TLS v1.2 connection 2. verify it's using the secure data connection

I'm new to unit tests, anything else that can be added to the unit tests? Many thanks.

This is what I have tried by following the first answer in this page:

@patch('ftplib.FTP_TLS', autospec=True)
    def test_open_ftp_connection(self, mock_ftp_constructor):
        mock_ftp = mock_ftp_constructor.return_value
        read_news_ftp_read.open_ftp_connection('test_host', 'test_username', 'test_password')

        mock_ftp_constructor.assert_called_with('test_host', 'test_username', 'test_password')
        self.assertTrue(mock_ftp.login.called)

This gave me error:

  File "C:\User\AppData\Local\Continuum\anaconda3\envs\Env-python3.7\lib\unittest\case.py", line 692, in assertTrue
    raise self.failureException(msg)
AssertionError: False is not true


Assertion failed
Fetterlock answered 1/3, 2021 at 17:15 Comment(5)
Doing anything external disqualifies the test to be a unit test. What you are trying to do is more an integration or end to end test.Coupon
Hi @KlausD. I'm just trying to figure out what the best way to write unit test for this...Fetterlock
For it to be a unit test you have to mock the FTP connection. In a unit test you don't test the ftplib, you also don't test the FTP connection. You are just testing if you are using the ftplib as it should be used. Use unittest.mock to replace ftplib.FTP_TLS with a Mock and test if the mock is used as planned.Coupon
@KlausD. Hi I have tried mock but got an error, I've updated my question, could you take a look for me please? Many thanks.Fetterlock
The mock stored the arguments to the constructor as attributes: e.g. mock_ftp_constructor.host.Coupon
P
0

Pay attention: Your ftp_connection() function doesn't call login() on ftp connection.

I don't see any login call in your production code. So the assert

self.assertTrue(mock_ftp.login.called)

will faill: so, if you just forgot to call login in your production code ... WOW the test worked like a charme and expose a production bug. Otherwise simply remove this assert.

Prokopyevsk answered 8/3, 2021 at 11:40 Comment(0)
L
0

I think you're asking a less than ideal question:

how I can write unit tests for this function, I'd like to test: 1.verify TLS v1.2 connection 2. verify it's using the secure data connection

Both of those things are outside of your control - the FTP server could be down, or changed, or its certificates could expire. That means your unit test would pass one time and fail the next with no changes, and that makes it a poor unit test because it's not testing a "unit" of your code.

A alternative is to create a FTP server for the duration of the test e.g. https://pytest-localftpserver.readthedocs.io You can then add dummy files to match what you expect to be on the server, run your code, then check that it output what you were expecting. This isn't a perfect solution, but it is a pragmatic one that should give you confidence in your code, but not take an immense amount of time and energy to setup and use.

Another alternative is to do an end-to-end test, where you contact an external server. It doesn't tell you if a specific version of your code works, e.g. to find the change that broke stuff, but it will tell you if it was working when the end-to-end test was run.

Lection answered 9/3, 2021 at 16:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.