使用twisted.trial.unittest时,反应器在测试之间停止

时间:2012-01-20 14:38:14

标签: python testing twisted reactor

有没有办法在测试之间保持联机?

我试图在运行多个测试集时保持用户记录,但注意到意外行为:每次测试后反应器停止(因此一旦建立的连接变得无法使用)。

为了探索这个,我准备了示例测试文件(下面)。

这将创建简单的侦听echo-server并将其存储在类字段中。 运行3次测试。 服务器期望在所有测试期间正确运行(实际上它只在第一次测试结束之前)。

示例:

#! /usr/bin/python
# -*- coding: utf-8 -*-

import logging

from twisted.python import log
from twisted.internet import defer, base, reactor
from twisted.trial import unittest
from twisted.internet.protocol import Protocol, Factory
from twisted.internet.endpoints import TCP4ServerEndpoint

observer = log.PythonLoggingObserver()
observer.start()
logging.basicConfig(level=logging.DEBUG)

class Echo(Protocol):
    '''Protocol from twistedmatrix examples'''
    def connectionMade(self):
        log.msg('Got incomming connection')
        self.transport.write("An apple a day keeps the doctor away\r\n")

    def connectionLost(self, reason):
        log.msg('Connection lost due to: %s' % reason)

    def dataReceived(self, data):
        self.transport.write(data)
        log.msg('Got some data: %s' % data)


class EchoFactory(Factory):
    '''Factory from twistedmatrix examples'''
    def buildProtocol(self, addr):
        return Echo()


class SampleTest(unittest.TestCase):
    '''Sample test case class derived straight from twisteds TestCase'''
    is_a_first_test = True
    endppoint = None
    def logLater(self, msgg = None):
        log.msg('called later message')

    @defer.inlineCallbacks
    def setUp(self):
        if self.__class__.is_a_first_test:
            self.__class__.endpoint = TCP4ServerEndpoint(reactor, 8007)
            self.__class__.endpoint.listen(EchoFactory())
            self.__class__.is_a_first_test = False

        log.msg('setting Up ... You may try (re)connecting now!!!')
        log.msg('We have endpoint: %s' % self.endpoint)
        yield reactor.callLater(5, self.logLater)
        log.msg('setUp done')

    def tearDown(self):
        log.msg('tearDown started')
        result = defer.Deferred()
        result.addCallback(self.logLater)
        reactor.callLater(5, result.callback, 'tearDown msg')
        log.msg('leaving tearDown')
        return result

    @defer.inlineCallbacks
    def test_00(self):
        log.msg('00 test body')
        sample_defer = defer.Deferred()
        sample_defer.addCallback(self.logLater)
        reactor.callLater(5, sample_defer.callback, 'Some sample action 00')
        log.msg('waiting reactor deferred')
        yield sample_defer
        log.msg('done with test body')

    @defer.inlineCallbacks
    def test_01(self):
        log.msg('01 test body')
        sample_defer = defer.Deferred()
        sample_defer.addCallback(self.logLater)
        reactor.callLater(5, sample_defer.callback, 'Some sample action 01')
        log.msg('waiting reactor deferred')
        yield sample_defer

    @defer.inlineCallbacks
    def test_02(self):
        log.msg('02 test body')
        sample_defer = defer.Deferred()
        sample_defer.addCallback(self.logLater)
        reactor.callLater(5, sample_defer.callback, 'Some sample action 02')
        log.msg('waiting reactor deferred')
        yield sample_defer

使用以下命令运行上面的文件:

trial test-file.py

在每次测试结束时显示“主循环终止”。 在该端口仍然在所有测试中监听之后(根据netstat -n4lt)。 但是在第二和第三测试体中连接telnet时没有回声(仅适用于第一个)。

Twisted doc http://twistedmatrix.com/documents/current/core/howto/testing.html#auto3说: “试验在一个过程中运行整个测试套件(超过四千个测试),单个反应器” (遗憾的是,我的twistedmatrix注册请求仍然未经过验证,因此无法在那里提出问题。)

在我的实际案例中,与服务器的连接花费的时间太长,无法为每个测试重复它,因此我希望每类案例至少执行一次。

那么,有没有办法在测试之间保持联机?

PS使用 python 2.7.1, python-twisted 10.2.0-1, Ubuntu 11.04

1 个答案:

答案 0 :(得分:2)

单元测试意味着孤立和独立。一个设置的连接不应该被另一个连接使用。

全球反应堆是一个不幸的共享可变状态。在可能的情况下,单元测试应该完全避免使用它。为了帮助隔离和独立,试验在测试方法之间(尽可能多地)重置它。无法禁用此功能。

由于您的连接设置成本很高,因此您应该调查为该连接创建经过验证的假冒。经过验证的伪造是某些API的替代实现,它通常(通常)对测试更友好(例如,创建假的应该是快速的),具有自己的单元测试集,证明它的行为与实际实现相同。

您的单元测试可以使用此经过验证的假冒,为每种测试方法创建一个新的假冒。这样可以避免违反隔离和独立性的问题,也可以让您的单元测试快速运行。