Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from twisted.trial.unittest import TestCase
- from twisted.protocols.amp import (
- Command, Integer, CommandLocator, BoxDispatcher, COMMAND, ASK, ANSWER)
- ################### Application code ###################
- class Sum(Command):
- arguments = [("a", Integer()), ("b", Integer())]
- response = [("result", Integer())]
- class Math(CommandLocator):
- @Sum.responder
- def sum(self, a, b):
- return {"result": a + b}
- class MathClient(object):
- """This is an example of application client code using C{callRemote}.
- It just provides a convenient abstraction around the application-defined
- AMP commands.
- """
- def __init__(self, protocol):
- """
- @param protocol: An C{AMP} instance connected to a remote L{Math}
- command locator.
- """
- self._protocol = protocol
- def sum(self, a, b):
- deferred = self._protocol.callRemote(Sum, a=a, b=b)
- return deferred.addCallback(lambda response: response["result"])
- ################### Application tests ###################
- class FakeBoxSender(object):
- def __init__(self):
- self.sent = []
- def sendBox(self, box):
- self.sent.append(box)
- class MathTest(TestCase):
- def setUp(self):
- super(MathTest, self).setUp()
- locator = Math()
- self.dispatcher = BoxDispatcher(locator)
- self.sender = FakeBoxSender()
- self.dispatcher.startReceivingBoxes(self.sender)
- def test_sum_request(self):
- """
- This is mainly a wiring test, asserting that L{Math.sum} is decorated
- with @Sum.responder.
- Incidentally it also exercises L{Sum.arguments} and implies that the
- 'a' and 'b' arguments are deserialized to C{int}s.
- One would ideally also test the L{Method.sum} on its own directly, by
- instantiating the L{Math} class, and really exercising all its actual
- logic.
- """
- box = {COMMAND: "Sum", ASK: "1", "a": "3", "b": "2"}
- self.dispatcher.ampBoxReceived(box)
- self.assertEqual(self.sender.sent, [{ANSWER: "1", "result": "5"}])
- def test_sum_response(self):
- """
- Maybe there should be a test for exercising L{Sum.response} too?
- It would directly or indirectly, make sure that the 'result' field is
- deserialized to C{int}.
- """
- class FakeBoxDispatcher(object):
- def __init__(self, locator):
- self.locator = locator
- def callRemote(self, commandType, *a, **kw):
- """
- Faking C{callRemote} this way is slightly unfortunate because it
- duplicates the real AMP logic a bit, but it might acceptable.
- """
- responder = self.locator.locateResponder(commandType.commandName)
- deferred = responder(kw)
- return deferred.addCallback(commandType.parseResponse, self)
- class MathClientTest(TestCase):
- def setUp(self):
- super(MathClientTest, self).setUp()
- locator = Math()
- dispatcher = FakeBoxDispatcher(locator)
- self.client = MathClient(dispatcher)
- def test_sum(self):
- """
- This tests L{MathClient}, and it does so by running a real L{Math}
- command locator, except that there is no network/transport involved.
- Other layers of the application code using L{MathClient} could as well
- have their tests setup using a real L{MatchClient} instantiated with
- a L{FakeBoxDispatcher} as well, as opposed to creating fake versions
- of L{MathClient}.
- This would of course make such higher-layer tests more "integration"
- and less "unit", but in practice it might be more convenient and
- give more confidence that mocking out L{MathClient} (drifting to
- state-based vs. behavior-based testing here, sorry).
- """
- deferred = self.client.sum(3, 2)
- self.assertEqual(5, self.successResultOf(deferred))
Advertisement
Add Comment
Please, Sign In to add comment