Distutils makes some call to the PyPI server to register and upload projects. Distutils2 will also make some calls to packages.python.org to automate the upload of documentation. This feature was added by Janis a while ago in Distribute and is being backported in Distutils2 during the GSOC.
To test all these features, what I usually did in Distutils was to monkey-patch the code that calls the server and record in memory the exchanges to check them. The problem with this approach is that you have to be careful in the way you patch the APIs the client code use. A typical bug that can happen is to get a slightly different behavior making your code buggy or broken when it interacts with the real server. Of course you can run your test once with the real server then use some mock or stub techniques. But this work can be rather tedious and complex in my opinion.
What I tend to do these days is drop completely this client-side test fixture approach, and just run a local server that implements partially or fully the real server API.
This blog post is just to demonstrate how easy it can be to run your own test server.
For HTTP protocols, the standard library provides everything needed to write such a server in a few lines. The wsgiref module for instance, is great to get a web server up and running during your tests.
Here's a full example (working for Python >= 2.6 and Python 3):
try: from urllib.request import urlopen except ImportError: from urllib2 import urlopen import time from wsgiref.simple_server import make_server, demo_app class AppRunner(threading.Thread): """Thread that wraps a wsgi app""" def __init__(self, wsgiapp=demo_app): threading.Thread.__init__(self) self.httpd = make_server('', 0, wsgiapp) self.address = self.httpd.server_address def run(self): self.httpd.serve_forever() def stop(self): self.httpd.shutdown() self.join() time.sleep(0.2) _SERVER = None def run_server(): """Runs the server.""" global _SERVER if _SERVER is not None: # we suppose it's running return _SERVER.address _SERVER = AppRunner() _SERVER.start() return _SERVER.address def stop_server(): """Stops the server.""" global _SERVER if _SERVER is None: return _SERVER.stop() _SERVER = None if __name__ == '__main__': # 1. set up print('Launching the test server') url, port = run_server() print('Test server running at %s:%d' % (url, port)) # 2. test try: print('Testing..') res = urlopen('http://%s:%d' % (url, port)) assert b'Hello world!' in res.read() finally: # 3. tear down print('Stopping the test server') stop_server()
run_server() and stop_server() are driving a thread that runs a wsgi application using the wsgiref helpers.
In the main section you can see an example of a test fixture, and of running a client test on the demo_app wsgi application wsgiref provides. It should return a "Hello world!" page. These functions are making sure there's only one server running even if run_server() is called several times, so it's dead easy to use it from a unittest class.
From there, writing a test server is just a matter of implementing a wsgi application that will replace the demo_app one. I find this technique superior to all the stub/mockup work required when you don't run your own server.
For other protocols than HTTP, this work can be longer and more complex of course, unless the sdtlib or a third party project already has a server implementation you can use (like smtpd).