我正在努力实现流协议,目前正在尝试使用新的实现进一步设置应用程序代码之前设置单元测试。
在创建测试的简单版本时,我遇到了使反应堆“变脏”的问题。我通过实现以下拆卸逻辑解决了该问题:
def tearDown(self):
def loseConnection(connection):
connection.transport.loseConnection()
# Closing all open connections
for _, connection in self.tcp_transport._connections.iteritems():
if isinstance(connection, Protocol):
connection.transport.loseConnection()
elif isinstance(connection, Deferred):
connection.addCallback(loseConnection)
简单的测试用例
def test_send_to_new_connection(self):
# Given
peerAddr = ('10.22.22.190', 5060)
# If
self.tcp_transport.send_to('test', peerAddr)
# Then
assert peerAddr in self.tcp_transport._connections
assert True == isinstance(self.tcp_transport._connections[peerAddr], Deferred)
在通过手动解析带有“ mock”值(不是真正的模拟,只是使用proto_helpers
创建虚假协议的延迟)来扩展测试用例时,测试用例开始失败,并显示相同的Reactor was unclean
消息,但是,在这种情况下,似乎现有的tearDown
逻辑无法处理清理工作。
扩展的测试用例不起作用
def test_send_to_new_connection(self):
# Given
peerAddr = ('10.22.22.190', 5060)
# If
self.tcp_transport.send_to('test', peerAddr)
# Then
assert peerAddr in self.tcp_transport._connections
assert True == isinstance(self.tcp_transport._connections[peerAddr], Deferred)
connection = _string_transport_connection(self.hostAddr, peerAddr, None, self.tcp_transport.connectionMade)
def assert_cache_updated_on_connection(connection):
print('--------- SUCCESS ----------')
peer = connection.transport.getPeer()
peerAddr = (peer.host, peer.port)
assert peerAddr in self.tcp_transport._connections
assert True == isinstance(self.tcp_transport._connections[peerAddr], Protocol)
def assert_fail(fail):
print('--------- FAIL ----------')
self.tcp_transport._connections[peerAddr].addCallback(assert_cache_updated_on_connection)
self.tcp_transport._connections[peerAddr].addErrback(assert_fail)
# Forcing deferred to fire with mock connection
self.tcp_transport._connections[peerAddr].callback(connection)
详细的错误消息
DirtyReactorAggregateError: Reactor was unclean.
Selectables:
<<class 'twisted.internet.tcp.Client'> to ('10.22.22.190', 5060) at 361e650>
根据此消息,我猜测仍有某个客户端悬空。我唯一的怀疑是被测试代码正在创建的TCP4ClientEndpoint,但由于连接的伪IP地址而无法成功连接。我很乐意清理它,但是问题是我不知道如何从延迟访问它:
def _createConnection(self, address):
endpoint = TCP4ClientEndpoint(reactor, address[0], address[1])
protocol = TCPProtocol(self.dataReceived, self.cacheConnection)
d = connectProtocol(endpoint, protocol)
...
return d
因此我可以访问d
,因为我可以通过模拟连接来解决它,但是如何访问最初为关闭该连接而创建的协议?