~sschwarzer/ftputil#88: 
Provide Docs for Mocking an FTP Server

Hi Stefan,

thank you for the nice ftputil library.

Please provide some docs how to test an application which does ftp transfer. It would be very nice if you could test the code without installing a real ftp server. This makes automated testing much easier.

Something like this:

ftp_host = MockedFTPHost(path_to_directory)

This way ftputil users can test the code without the need for a real ftp server.

Or do you have a different or better solution?

Thomas Güttler

Status
REPORTED
Submitter
ftputiluser (unverified)
Assigned to
No-one
Submitted
9 years ago
Updated
9 years ago
Labels
documentation enhancement

schwa (unverified) 9 years ago · edit

Thanks for the thanks, you're welcome. :-)

From your description, I guess you want to run your code against the MockFTPHost instead of the normal FTPHost. The interesting part is: how do you want MockFTPHost to behave? Do you imagine something like a virtual in-memory FTP server? If MockFTPHost was implemented this way, the following example should work:

host = ftputil.MockFTPHost("some_host", "some_user", "the_password")
host.mkdir("test_directory")
with host.open("test_directory/remote_file", "w") as fobj:
    fobj.write("Content")
host.chdir("test_directory")
print(host.stat("remote_file"))  # (33188, None, None, 1, '0', '0', 641, None, 1248213600.0, None)
with host.open("remote_file", "r") as fobj:
    print(fobj.read())  # "Content"

So MockFTPHost would need to keep all the file system state (directory structure including files, stat information and file contents), so that you can still navigate the directory structure and the files you created.

Even though this would be a "perfect" "imitation" of the FTPHost class, it would still not allow you to test a few things:

  • login failures
  • directories/files owned by other users
  • existing, but unreadable directories/files
  • ...

So if you wanted to test things like this, this would require API extensions to "tell" the mock host to behave in these "anomal" ways.

A simpler approach could be to mock the session factory you pass into the FTPHost constructor. I use this approach in many of my unit tests. Have a look at test/mock_ftplib.py. But although this contains a lot of functionality, it probably doesn't have a good API and may be too low-level for your taste. Also, in the current form you would need to monkey-patch the module to use your own directory contents.

Another approach to mock FTPHost instances might be to use the ​mock library, which is included in Python 3.3 and up, but can also be used with Python versions 2.5, 2.6, 2.7, 3.1 and 3.2. I've used the library in other projects and like it. Actually, I've thought of rewriting a good part of the mock tests in ftputil by using the mentioned mock library. (It wasn't around when I started the ftputil project over ten years ago. :-) ) If you haven't already, I suggest you have a look at it, too.

What do you think?

ftputiluser (unverified) 9 years ago · edit

Hi Stefan,

we use the mock library a lot (with Python 2.7).

I think the most basic FTP features (upload, download, stat) should be implemented. Special stuff like login failures and files owned by other users need not to be implemented.

In-memory would be a solution, but I would just take an existing directory. The MockedFTPHost should serve this local directory like a remote directory.

This would make it much easier to test applications which use ftputil.

What do you think?

Thomas Güttler

schwa (unverified) 9 years ago · edit

Replying to ftputiluser:

we use the mock library a lot (with Python 2.7).

Did you try it for mocking FTPHost?

I think the most basic FTP features (upload, download, stat) should be implemented. Special stuff like login failures and files owned by other users need not to be implemented.

Um, I have the odd feeling that different people will consider different things "basic" or "special". ;-/

I think it would depend on which level you're testing. If you want to test the layer that speaks directly to FTPHost, I'd think that the features you call "special" would be rather important, especially the things you can't easily do even with a real FTP server (e. g. simulate an unreachable host).

From our conversation so far I have the impression you want the MockFTPHost rather to test the higher levels so they have a "virtual back end" to "speak with".

In-memory would be a solution, but I would just take an existing directory. The MockedFTPHost should serve this local directory like a remote directory.

I'm not sure if this would be actually easier to implement than an in-memory data structure, but I wouldn't necessarily need an API for preparing the mock environment (the FTP directory). On the other hand, by using a directory, this becomes less of a mock implementation. For example, if you have a real directory, you can't create a file owned by another user unless you can create new users or have a colleague nearby.

This would make it much easier to test applications which use ftputil.

If I implemented a MockFTPHost, it would probably use the in-memory approach. Using a directory would reduce the things you can mock seriously (depending on what you want/need to test). There are things you can't easily mock with an in-memory approach (like huge files that would fill the computer's memory), but I think these situations are less important as probably a "semi-huge" file would do.

I think implementing the MockFTPHost could well amount to a lot of work and I wonder if this time shouldn't be put into other features.

On the other hand, I've wanted to clean up the ftputil unit tests for quite some time and I'll think about whether there are synergies and how I would design the MockFTPHost.

If a MockFTPHost gets implemented, it will certainly take some time, so for now I suggest you

  • try the mock library if you want to test a layer close to ftputil, or
  • set up a real FTP server if you want to test higher levels (I'm aware this is work, but maybe it's less difficult than you might think. I'm using ​PureFTPd for some tests, but I also heard good things about ​pyftpdlib, implemented in Python.

schwa (unverified) 9 years ago · edit

For the use case of testing higher application levels, before I even start implementing a MockFTPHost, I'd download pyftpdlib and give it a try. If it's really easy to set up, a wiki page on this setup could be a reasonable alternative to implementing a MockFTPHost.

ftputiluser (unverified) 9 years ago · edit

Hi Stefan,

the subject of this ticket is "Provide Docs for Mocking an FTP Server". A MockFTPHost was just one solution I thought about.

I heard good things about pyftpdlib, too. I guess this is better than my initial idea of a MockFTPHost.

I guess this should make it possible to do automated testing (for example continuous integration) without a complicated and platform specific dependency on a running ftp server.

schwa (unverified) 9 years ago · edit

I suppose there should be some advice on mock testing in the documentation. I had gotten another question on this topic recently and can well imagine there's a real need for this. (Continuous integration is a good point.)

schwa (unverified) 9 years ago · edit

Replying to schwa:

I suppose there should be some advice on mock testing in the documentation.

Or maybe it should be a wiki page and a link to it in the documentation.

Register here or Log in to comment, or comment via email.