View difference between Paste ID: i6Nj7CD2 and m0ADSLuj
SHOW: | | - or go back to the newest paste.
1
from twisted.trial.unittest import TestCase
2
from twisted.protocols.amp import (
3
    Command, Integer, CommandLocator, BoxDispatcher, COMMAND, ASK, ANSWER)
4
5
################### Application code ###################
6
7
8
class Sum(Command):
9
10
    arguments = [("a", Integer()), ("b", Integer())]
11
    response = [("result", Integer())]
12
13
14
class Math(CommandLocator):
15
16
    @Sum.responder
17
    def sum(self, a, b):
18
        return {"result": a + b}
19
20
21
class MathClient(object):
22
    """This is an example of application client code using C{callRemote}.
23
24
    It just provides a convenient abstraction around the application-defined
25
    AMP commands.
26
    """
27
28
    def __init__(self, protocol):
29
        """
30
        @param protocol: An C{AMP} instance connected to a remote L{Math}
31
            command locator.
32
        """
33
        self._protocol = protocol
34
35
    def sum(self, a, b):
36
        deferred = self._protocol.callRemote(Sum, a=a, b=b)
37
        return deferred.addCallback(lambda response: response["result"])
38
39
40
################### Application tests ###################
41
42
43
class FakeBoxSender(object):
44
45
    def __init__(self):
46
        self.sent = []
47
48
    def sendBox(self, box):
49
        self.sent.append(box)
50
51
52
class MathTest(TestCase):
53
54
    def setUp(self):
55
        super(MathTest, self).setUp()
56
        self.locator = Math()
57
        self.dispatcher = BoxDispatcher(self.locator)
58
        self.sender = FakeBoxSender()
59
        self.dispatcher.startReceivingBoxes(self.sender)
60
61
    def test_sum_request(self):
62
        """
63
        This is mainly a wiring test, asserting that L{Math.sum} is decorated
64
        with @Sum.responder.
65
66
        Incidentally it also exercises L{Sum.arguments} and implies that the
67
        'a' and 'b' arguments are deserialized to C{int}s.
68
69
        One would ideally also test the L{Method.sum} on its own directly, by
70
        instantiating the L{Math} class, and really exercising all its actual
71
        logic.
72
        """
73
        box = {COMMAND: "Sum", ASK: "1", "a": "3", "b": "2"}
74
        self.dispatcher.ampBoxReceived(box)
75
        self.assertEqual(self.sender.sent, [{ANSWER: "1", "result": "5"}])
76
77
    def test_sum_response(self):
78
        """
79
        Maybe there should be a test for exercising L{Sum.response} too?
80
81
        It would directly or indirectly, make sure that the 'result' field is
82
        deserialized to C{int}.
83
        """
84
85
86
class FakeBoxDispatcher(object):
87
88
    def __init__(self, locator):
89
        self.locator = locator
90
91
    def callRemote(self, commandType, *a, **kw):
92
        """
93
        Faking C{callRemote} this way is slightly unfortunate because it
94
        duplicates the real AMP logic a bit, but it might acceptable.
95
        """
96
        responder = self.locator.locateResponder(commandType.commandName)
97
        deferred = responder(kw)
98
        return deferred.addCallback(commandType.parseResponse, self)
99
100
101
class MathClientTest(TestCase):
102
103
    def setUp(self):
104
        super(MathClientTest, self).setUp()
105
        locator = Math()
106
        dispatcher = FakeBoxDispatcher(locator)
107
        self.client = MathClient(dispatcher)
108
109
    def test_sum(self):
110
        """
111
        This tests L{MathClient}, and it does so by running a real L{Math}
112
        command locator, except that there is no network/transport involved.
113
114
        Other layers of the application code using L{MathClient} could as well
115
        have their tests setup using a real L{MatchClient} instantiated with
116
        a L{FakeBoxDispatcher} as well, as opposed to creating fake versions
117
        of L{MathClient}.
118
119
        This would of course make such higher-layer tests more "integration"
120
        and less "unit", but in practice it might be more convenient and
121
        give more confidence that mocking out L{MathClient} (drifting to
122
        state-based vs. behavior-based testing here, sorry).
123
        """
124
        deferred = self.client.sum(3, 2)
125
        self.assertEqual(5, self.successResultOf(deferred))