- Test client code doesn’t have to care about the specific HTTP port. Any free port can be used by the test without interference with other running processes.
- The HTTP server is up and running when the test is ready.
- Resource handling uses the the with statement. The HTTP server is shut-down at the end of the test.
- The concrete request urls (host and port) are transparent for the test.
- Test can be run fully in memory. The only resource allocated is the HTTP socket.
with http_server(Handler) as url: assert list(urllib2.urlopen(url("/resource"))) == [content]To run this test we need a HTTP handler implementation. You could use the SimpleHTTPServer.SimpleHTTPRequestHandler that comes with python and work with files served from a directory. This is any good point to start but setting up a test folder with the necessary content is cumbersome and inflexible.
This handler runs in memory without any additional setup. It will always returns with the 200 response code writes the content into the request.
code, content = 200, "Ok" class Handler(BaseHTTPServer.BaseHTTPRequestHandler): def do_GET(self): self.send_response(code) self.wfile.write("\n" + content )The http_server implementation starts a thread, opens a socket and yields the url function. The HTTP request handler runs in the spawned thread.
@contextlib.contextmanager def http_server(handler): def url(port, path): return 'http://%s:%s%s' % (socket.gethostname(), port, path) httpd = SocketServer.TCPServer(("", 0), handler) t = threading.Thread(target=httpd.serve_forever) t.setDaemon(True) t.start() port = httpd.server_address yield functools.partial(url, port) httpd.shutdown()I leave it as an exercise to you to write an implementation that reuses the HTTP server in multiple tests. This could be necessary if the overhead of allocating ports dominates the test running time.