问题
Within my code, I use task.LoopingCall() to run some deferred function every second. I want to make sure that that function returns the right values for a certain number of things. So, I thought I could use a task.clock() and call the advance() method on it. However, I am not getting the right number of responses expected.
Any idea what I am doing wrong?
Here is a test code to show what I mean. First is the server:
from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor
from twisted.internet import task
import time
class Chat(LineReceiver):
def __init__(self):
self.echo = None
def connectionMade(self):
self.echo = task.LoopingCall(self.echo_print)
self.echo.start(1)
def connectionLost(self, reason='whatever'):
if self.echo is not None and self.echo.running:
self.echo.stop()
def lineReceived(self, line):
if line == 'stop':
self.echo.stop()
def echo_print (self):
self.sendLine("Echo")
class ChatFactory(Factory):
def __init__(self):
pass
def buildProtocol(self, addr):
return Chat()
if __name__ == "__main__":
reactor.listenTCP(8123, ChatFactory())
reactor.run()
And now the test case:
from twisted.internet import task, base
from twisted.trial import unittest
from twisted.test import proto_helpers
from chat import ChatFactory
class TestChat (unittest.TestCase):
def setUp (self):
self.factory = ChatFactory()
self.clock = task.Clock()
self.proto = self.factory.buildProtocol(('127.0.0.1', 0))
self.tr = proto_helpers.StringTransport()
self.proto.callLater = self.clock.callLater
self.proto.makeConnection(self.tr)
def tearDown (self):
if self.proto:
self.proto.connectionLost()
def test_echo (self):
self.proto.dataReceived('ook\n')
seconds_elapsed = 5
self.clock.advance(seconds_elapsed)
expected = 'Echo\r\n' * seconds_elapsed
self.assertEqual(self.tr.value(), expected)
When I run py.test on this, I get:
E FailTest: not equal:
E a = 'Echo\r\n'
E b = 'Echo\r\nEcho\r\nEcho\r\nEcho\r\nEcho\r\n'
Note that adding import time; time.sleep(5) does indeed make the test pass. So, I suspect that the problem is that the task.clock is not used correctly.
回答1:
I believe that I have found the problems.
LoopingCallis using the reactor by default. I needed to set it up so that it used my own clock via the class variableclock. See task.clock class documentation.self.clock.advance(x)sets the clock to be at timex. It does not go through(x-1, x-2, ..., now)and thus any deferred that should run on those intermediate steps will not run. Hence, the error in the test is correct behaviour. Callingself.clock.advance(1)within a loop starting at 0 and ending inseconds_elapseddid have the desired effect.
The Twisted section on unit tests is worth reading a few times so you get familiar with what is going on. If you have more problems, look at the twisted internal unit tests!
来源:https://stackoverflow.com/questions/14609888/how-to-test-loopingcall