如何在单元测试中杀死套接字以进行重新连接测试

时间:2012-10-17 00:01:13

标签: python unit-testing sockets

我正在尝试测试一些在断开连接后重新连接到服务器的代码。这在测试之外完全正常,但是在运行测试时它无法确认套接字已断开连接。

我正在使用Gevent Stream Server来模拟真实的侦听服务器:

import gevent.server
from gevent import queue


class TestServer(gevent.server.StreamServer):

    def __init__(self, *args, **kwargs):
        super(TestServer, self).__init__(*args, **kwargs)
        self.sockets = {}

    def handle(self, socket, address):
        self.sockets[address] = (socket, queue.Queue())
        socket.sendall('testing the connection\r\n')
        gevent.spawn(self.recv, address)

    def recv(self, address):
        socket = self.sockets[address][0]
        queue = self.sockets[address][1]
        print 'Connection accepted %s:%d' % address
        try:
            for data in socket.recv(1024):
                queue.put(data)
        except:
            pass

    def murder(self):
        self.stop()
        for sock in self.sockets.iteritems():
            print sock
            sock[1][0].shutdown(socket.SHUT_RDWR)
            sock[1][0].close()
        self.sockets = {}


def run_server():
    test_server = TestServer(('127.0.0.1', 10666))
    test_server.start()
    return test_server

我的测试看起来像这样:

def test_can_reconnect(self):
    test_server = run_server()
    client_config = {'host': '127.0.0.1', 'port': 10666}
    client = Connection('test client', client_config, get_config())
    client.connect()
    assert client.socket_connected
    test_server.murder()
    #time.sleep(4) #tried sleeping. no dice.
    assert not client.socket_connected
    assert client.server_disconnect
    test_server = run_server()
    client.reconnect()
    assert client.socket_connected

assert not client.socket_connected失败。

我在recv期间检测到“not data”。如果它是None,那么我设置一些变量,以便其他代码可以决定是否重新连接(如果是user_disconnect则不重新连接,等等)。这种行为起作用,过去一直对我有用,我直到现在才尝试对它进行测试。套接字连接和本地函数范围有什么奇怪之处吗?就像停止服务器后连接仍然存在一样。

我正在尝试测试的代码是开放的:https://github.com/kyleterry/tenyks.git

如果您运行测试,您将看到我正在尝试修复的测试失败。

4 个答案:

答案 0 :(得分:2)

尝试使用真正的套接字运行单元测试是一个艰难的行。这将是棘手的,因为一次只能运行一组测试,因为将使用服务器端口,并且随着套接字的设置和拆除,它将会变慢。最重要的是,如果这实际上是一个单元测试,你不想测试套接字,只需要使用套接字的代码。

如果你模拟套接字调用,你可以从模拟的代码中抛出异常,并确保使用套接字的代码做正确的事情。你不需要一个真正的套接字来确保被测试的类做正确的事情,你可以伪造它,如果你可以将套接字调用包装在一个对象中。在构建类时传递对套接字对象的引用,然后您就可以开始了。

我的建议是将套接字调用包装在一个支持sendall,recv和您在套接字上调用的所有方法的类中。然后你可以用TestReconnectSocket(或其他)替换实际的Socket类并运行你的测试。

看看mox,一个python模拟框架。

答案 1 :(得分:0)

模糊的回应,但我的立即反应是你的recv()调用阻塞并使套接字保持活动状态 - 你是否尝试使套接字无阻塞,并在关闭时捕获错误?

答案 2 :(得分:0)

在测试这样的套接字时要记住的一件事是,操作系统不喜欢在使用后立即重新打开套接字。您可以设置套接字选项以告知它继续并重新使用它。在创建套接字后立即设置套接字的选项:

mysocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

希望这可以解决您的问题。您可能必须在服务器端和客户端都这样做,具体取决于哪一个给您带来问题。

答案 3 :(得分:0)

  • 您正在呼叫shutdown(socket.SHUT_RDWR),因此这似乎不是problem with recv blocking
  • 但是,您使用的是gevent.socket.socket.recv,因此请检查您的gevent版本,recv()存在导致block if the underlying file descriptor is closed问题的问题}(版本< v0.13.0
  • 您可能仍需要gevent.sleep()合作收益,并让客户有机会退出recv()来电。