Tornado unit test with web sockets - what about st

2019-03-31 19:02发布

问题:

I've been using tornado server for a while and I have to say I like it. I have a tornado server (which runs on python3.2) that handles web socket and http requests. What I want to do is to write some unit tests (which use web sockets) with ws2py (which implements a ws client to use with the tornado IOLoop). I see tornado has the AsyncTestCase class which looks quite interesting especially when used with an AsyncHTTPClient as stated in its doc:

class MyTestCase2(AsyncTestCase):
    def test_http_fetch(self):
        client = AsyncHTTPClient(self.io_loop)
        client.fetch("http://www.tornadoweb.org/", self.stop)
        response = self.wait()
        # Test contents of response
        self.assertIn("FriendFeed", response.body)

I would like to use AsyncTestCase with web sockets, The client is not a problem, i can send and receive messages without problems.

I guess what I have to do is to pass self.stop to the client as callback in order to retrieve the received message by calling wait() like in the example above. But somehow this does not work, here is what i have:

class SQLRequests(AsyncTestCase):
    """Tests sql requests"""

    def test_sql_req_1(self):
        """first test function"""
        client = AsyncWSClient(httpBaseUrl, self.io_loop)
        client.sendMessage('some_message', self.stop)

        response = self.wait()
        if response.data:
            print('got %s' % str(response.data))
            # some test
            self.assertTrue(True)


if __name__ == '__main__':
    unittest.main()

This is my web socket client:

class AsyncWSClient(TornadoWebSocketClient):
"""
Asynchronous web socket client based on ws4py's tornadoclient
Sends a message and calls callback with received message
"""
def __init__(self, url, ioLoop=None, **kwargs):
    TornadoWebSocketClient.__init__(self, url, io_loop=ioLoop, **kwargs)
    self._callback = None
    self._message = None

def opened(self):
    """called when web socket opened"""
    self.send(self._message, binary=False)      

def received_message(self, message):
    """Received a message"""
            self.close()
    if self._callback:
        self._callback(message)

def sendMessage(self, message, callback):
    """Connects and sends message when connected"""
    self._message = message
    self._callback = callback
    self.connect()

I do receive a ws2py.messaging.TextMessage object as response, but its data field it None although some data has been received by the client. If I have a look into the AsyncTestCase, before it calls the callback, that object has some data in it, which disappears somewhere somehow when it is passed as return value of wait().

I see there is a mystical thing in tornado called stack_context, has that something to do with my problem?

回答1:

The problem is that the message "data" is contained in the data attribute of message. Once received_message is called, message.data is reset to None (https://github.com/Lawouach/WebSocket-for-Python/blob/master/ws4py/websocket.py#L369).

So, just call your callback passing message.data rather than the full message. Like that:

def received_message(self, message):
    """Received a message"""
    self.close()
    if self._callback:
       self._callback(message.data)