I want to write a test for my code which uses a ftp library and does upload data via ftp.
I would like to avoid the need for a real ftp server in my test.
What is the most simple way to test my code?
There are several edge-cases which I would like to test.
For example: my code tries to create a directory which already exists.
I want to catch the exception and do appropriate error handling.
I know that I could use the mocking library. I used it before. But maybe there is a better solution for this use case?
Update Why I don't want to do mocking: I know that I could use mocking to solve this. I could mock the library I use (I use ftputil from Stefan Schwarzer) and test my code this way. But what happens if I change my code and use a different ftp library in the future? Then I would need to re-write my testing code, too. I am lazy. I want to be able to rewrite the real code I am testing without touching the test code. But maybe I am still missing a cool way to use mocking.
2 Answers
Answers 1
Firstly to hey this or of the way. You aren't asking about Mocking, your question is about Faking.
Fake, an implementation of an interface, which expresses correct behaviour, but cannot be used in production.
Mock, an implementation of an interface that responds to interactions based on a scripted (script as in movie script, not uncompiled code) response.
Stub, an implementation of an interface lacking any real implementation. Usually used in mcguffin style tests.
Notice that in every case the word "interface" is used.
Your question asks how to Fake a TCP port such that the behaviour is a FTP server, with STATE of a rw filesystem underneath.
This is hard.
It is much easier to MOCK an internal interface that throws when you call the mkdir function.
If you must FAKE a FTP server. I suggest creating a docker container with the server in the state you want and use docker to handle the repeatability and lifecycle of the FTP server.
Answers 2
ContextManager:
class FTPServerContext(object): banner = 'FTPServerContext ready' def __init__(self, directory_to_serve): self.directory_to_serve = directory_to_serve def __enter__(self): cmd = ['serve_directory_via_ftp'] self.pipe = subprocess.Popen(cmd, cwd=self.directory_to_serve) time.sleep(2) # TODO check banner via https://stackoverflow.com/a/4896288/633961 def __exit__(self, *args): self.pipe.kill()
console_script:
def serve_directory_via_ftp(): # https://pyftpdlib.readthedocs.io/en/latest/tutorial.html authorizer = DummyAuthorizer() authorizer.add_user('testuser-ftp', 'testuser-ftp-pwd', '.', perm='elradfmwMT') handler = FTPHandler handler.authorizer = authorizer handler.banner = testutils.FTPServerContext.banner address = ('localhost', 2121) server = FTPServer(address, handler) server.serve_forever()
Usage in test:
def test_execute_job_and_create_log(self): temp_dir = tempfile.mkdtemp() with testutils.FTPServerContext(temp_dir) as ftp_context: execute_job_and_create_log(...)
Code is in the public domain under any license you want. It would great if you make this a pip installable package at pypi.org.
0 comments:
Post a Comment