Python: unit testing socket-based code?

David Wolever picture David Wolever · Oct 29, 2010 · Viewed 12.8k times · Source

I'm writing a Python client+server that uses gevent.socket for communication. Are there any good ways of testing the socket-level operation of the code (for example, verifying that SSL connections with an invalid certificate will be rejected)? Or is it simplest to just spawn a real server?

Edit: I don't believe that "naive" mocking will be sufficient to test the SSL components because of the complex interactions involved. Am I wrong in that? Or is there a better way to test SSL'd stuff?

Answer

Denis Bilenko picture Denis Bilenko · Oct 29, 2010

You can easily start a server and then access it in a test case. The gevent's own test suite does exactly that for testing gevent's built-in servers.

For example:

class SimpleServer(gevent.server.StreamServer):

    def handle(self, socket, address):
        socket.sendall('hello and goodbye!')

class Test(unittest.TestCase):      

    def test(self):
        server = SimpleServer(('127.0.0.1', 0))
        server.start()
        client = gevent.socket.create_connection(('127.0.0.1', server.server_port))
        response = client.makefile().read()
        assert response == 'hello and goodbye!'
        server.stop()

Using 0 for the port value means the server will use any available port. After the server is started, the actual value chosen by bind is available as server_port attribute.

StreamServer supports SSL too, pass keyfile and certfile arguments to the constructor and it will wrap each socket with SSLObject before passing it to your handler.

If you don't use StreamServer and your server is based on Greenlet then indeed spawning it is what you should do. Don't forget to kill it at the end of the test case.

Starting a server and spawning a greenlet are fast operations in gevent, much faster than creating a new thread or process and you can easily create a new server for each test case. Just don't forget to cleanup as soon as you don't need the server anymore.

I believe there's no need to mock any of gevent API, it's much easier just to use it as servers and clients can happily live within the same process.