Imported Upstream version 12.1.0
[contrib/python-twisted.git] / doc / core / howto / trial.html
1 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE html  PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'  'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
2   <head>
3 <title>Twisted Documentation: Test-driven development with Twisted</title>
4 <link href="stylesheet.css" rel="stylesheet" type="text/css"/>
5   </head>
6
7   <body bgcolor="white">
8     <h1 class="title">Test-driven development with Twisted</h1>
9     <div class="toc"><ol><li><a href="#auto0">Introductory example of Python unit testing</a></li><li><a href="#auto1">Creating an API and writing tests</a></li><li><a href="#auto2">Making the tests pass</a></li><ul><li><a href="#auto3">Factoring out common test logic</a></li></ul><li><a href="#auto4">Twisted specific testing</a></li><li><a href="#auto5">Testing a protocol</a></li><ul><li><a href="#auto6">Creating and testing the server</a></li><li><a href="#auto7">Creating and testing the client</a></li></ul><li><a href="#auto8">More good practices</a></li><ul><li><a href="#auto9">Testing scheduling</a></li><li><a href="#auto10">Cleaning up after tests</a></li><li><a href="#auto11">Handling logged errors</a></li></ul><li><a href="#auto12">Resolve a bug</a></li><li><a href="#auto13">Code coverage</a></li><li><a href="#auto14">Conclusion</a></li></ol></div>
10     <div class="content">
11
12 <span/>
13
14 <p>Writing good code is hard, or at least it can be. A major challenge is
15 to ensure that your code remains correct as you add new functionality.</p>
16
17 <p><a href="http://en.wikipedia.org/wiki/Unit_test" shape="rect">Unit testing</a> is a
18 modern, light-weight testing methodology in widespread use in many
19 programming languages. Development that relies on unit tests is often
20 referred to as Test-Driven Development 
21 (<a href="http://en.wikipedia.org/wiki/Test-driven_development" shape="rect">TDD</a>). 
22 Most Twisted code is tested using TDD.</p>
23
24 <p>To gain a solid understanding of unit testing in Python, you should read
25 the <a href="http://docs.python.org/library/unittest.html" shape="rect">unittest --
26 Unit testing framework chapter</a> of the <a href="http://docs.python.org/library/index.html" shape="rect">Python Library
27 Reference</a>. There is also a ton of information available online and in
28 books.</p>
29
30 <h2>Introductory example of Python unit testing<a name="auto0"/></h2>
31
32 <p>This document is principally a guide to Trial, Twisted's unit testing
33 framework. Trial is based on Python's unit testing framework. While we do not
34 aim to give a comprehensive guide to general Python unit testing, it will be
35 helpful to consider a simple non-networked example before expanding to cover a
36 networking code that requires the special capabilities of Trial. If you are
37 already familiar with unit test in Python, jump straight to the section
38 specific to <a href="#twisted" shape="rect">testing Twisted code</a>.</p>
39
40 <p><div class="note"><strong>Note: </strong>In what follows we will make a series of refinements
41 to some simple classes. In order to keep the examples and source code links
42 complete and to allow you to run Trial on the intermediate results at every
43 stage, I add <code>_N</code> (where the <code>N</code> are successive
44 integers) to file names to keep them separate. This is a minor visual
45 distraction that should be ignored.</div></p>
46
47 <h2>Creating an API and writing tests<a name="auto1"/></h2>
48
49 <p>We'll create a library for arithmetic calculation. First, create a
50 project structure with a directory called <code class="shell">calculus</code> containing an empty <code class="py-filename">__init__.py</code> file.</p>
51
52 <p>Then put the following simple class definition API into <code class="py-filename">calculus/base_1.py</code>:</p>
53
54 <div class="py-listing"><pre><p class="py-linenumber"> 1
55  2
56  3
57  4
58  5
59  6
60  7
61  8
62  9
63 10
64 11
65 12
66 13
67 14
68 15
69 16
70 </p><span class="py-src-comment"># -*- test-case-name: calculus.test.test_base_1 -*-</span>
71
72
73
74 <span class="py-src-keyword">class</span> <span class="py-src-identifier">Calculation</span>(<span class="py-src-parameter">object</span>):
75     <span class="py-src-keyword">def</span> <span class="py-src-identifier">add</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
76         <span class="py-src-keyword">pass</span>
77
78     <span class="py-src-keyword">def</span> <span class="py-src-identifier">subtract</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
79         <span class="py-src-keyword">pass</span>
80
81     <span class="py-src-keyword">def</span> <span class="py-src-identifier">multiply</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
82         <span class="py-src-keyword">pass</span>
83
84     <span class="py-src-keyword">def</span> <span class="py-src-identifier">divide</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
85         <span class="py-src-keyword">pass</span>
86 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/base_1.py"><span class="filename">listings/trial/calculus/base_1.py</span></a></div></div>
87
88 <p>(Ignore the <code class="python">test-case-name</code> comment for
89 now. You'll see why that's useful <a href="#comment" shape="rect">below</a>.)</p>
90
91 <p>We've written the interface, but not the code. Now we'll write a set of
92 tests. At this point of development, we'll be expecting all tests to
93 fail. Don't worry, that's part of the point. Once we have a test framework
94 functioning, and we have some decent tests written (and failing!), we'll go
95 and do the actual development of our calculation API. This is the preferred
96 way to work for many people using TDD - write tests first, make sure they
97 fail, then do development. Others are not so strict and write tests after
98 doing the development.</p>
99
100 <p>Create a <code class="shell">test</code> directory beneath <code class="shell">calculus</code>, with an empty <code class="py-filename">__init__.py</code> file. In a <code class="py-filename">calculus/test/test_base_1.py</code>, put the
101 following:</p>
102
103 <div class="py-listing"><pre><p class="py-linenumber"> 1
104  2
105  3
106  4
107  5
108  6
109  7
110  8
111  9
112 10
113 11
114 12
115 13
116 14
117 15
118 16
119 17
120 18
121 19
122 20
123 21
124 22
125 23
126 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">base_1</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Calculation</span>
127 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">trial</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">unittest</span>
128
129 <span class="py-src-keyword">class</span> <span class="py-src-identifier">CalculationTestCase</span>(<span class="py-src-parameter">unittest</span>.<span class="py-src-parameter">TestCase</span>):
130     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_add</span>(<span class="py-src-parameter">self</span>):
131         <span class="py-src-variable">calc</span> = <span class="py-src-variable">Calculation</span>()
132         <span class="py-src-variable">result</span> = <span class="py-src-variable">calc</span>.<span class="py-src-variable">add</span>(<span class="py-src-number">3</span>, <span class="py-src-number">8</span>)
133         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">result</span>, <span class="py-src-number">11</span>)
134
135     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_subtract</span>(<span class="py-src-parameter">self</span>):
136         <span class="py-src-variable">calc</span> = <span class="py-src-variable">Calculation</span>()
137         <span class="py-src-variable">result</span> = <span class="py-src-variable">calc</span>.<span class="py-src-variable">subtract</span>(<span class="py-src-number">7</span>, <span class="py-src-number">3</span>)
138         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">result</span>, <span class="py-src-number">4</span>)
139
140     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_multiply</span>(<span class="py-src-parameter">self</span>):
141         <span class="py-src-variable">calc</span> = <span class="py-src-variable">Calculation</span>()
142         <span class="py-src-variable">result</span> = <span class="py-src-variable">calc</span>.<span class="py-src-variable">multiply</span>(<span class="py-src-number">12</span>, <span class="py-src-number">5</span>)
143         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">result</span>, <span class="py-src-number">60</span>)
144
145     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_divide</span>(<span class="py-src-parameter">self</span>):
146         <span class="py-src-variable">calc</span> = <span class="py-src-variable">Calculation</span>()
147         <span class="py-src-variable">result</span> = <span class="py-src-variable">calc</span>.<span class="py-src-variable">divide</span>(<span class="py-src-number">12</span>, <span class="py-src-number">5</span>)
148         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">result</span>, <span class="py-src-number">2</span>)
149 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/test/test_base_1.py"><span class="filename">listings/trial/calculus/test/test_base_1.py</span></a></div></div>
150
151 <p>You should now have the following 4 files:
152
153 <pre class="shell" xml:space="preserve">
154     calculus/__init__.py
155     calculus/base_1.py
156     calculus/test/__init__.py
157     calculus/test/test_base_1.py
158 </pre>
159 </p>
160
161 <p>To run the tests, there are two things you must get set up. Make sure
162 you get these both done - nothing below will work unless you do.</p>
163
164 <p>First, make sure that the directory that <em>contains</em> your
165  <code class="shell">calculus</code> directory is in your Python load path. If you're
166 using the Bash shell on some form of unix (e.g., Linux, Mac OS X), run
167  <code class="shell">PYTHONPATH=&quot;$PYTHONPATH:`pwd`/..&quot;</code> at
168 the command line in the <code class="shell">calculus</code> directory. Once you have your
169 Python path set up correctly, you should be able to run Python from the
170 command line and <code class="python">import calculus</code> without seeing
171 an import error.</p>
172
173 <p>Second, make sure you can run the <code class="shell">trial</code>
174 command. That is, make sure the directory containing the <code class="shell">trial</code>
175 program on you system is in your shell's <code class="shell">PATH</code>. The easiest way to check if you have this is to
176 try running <code class="shell">trial --help</code> at the command line. If
177 you see a list of invocation options, you're in business. If your shell
178 reports something like <code class="shell">trial: command not found</code>,
179 make sure you have Twisted installed properly, and that the Twisted
180  <code class="shell">bin</code> directory is in your <code class="shell">PATH</code>. If
181 you don't know how to do this, get some local help, or figure it out by
182 searching online for information on setting and changing environment
183 variables for you operating system.</p>
184
185 <p>With those (one-time) preliminary steps out of the way, let's perform
186 the tests. Run <code class="shell">trial calculus.test.test_base_1</code> from the
187 command line from the <code class="shell">calculus</code> directory.
188
189 You should see the following output (though your files are probably not in
190  <code class="shell">/tmp</code>:</p>
191
192 <pre class="shell" xml:space="preserve">
193 $ trial calculus.test.test_base_1
194 calculus.test.test_base_1
195   CalculationTestCase
196     test_add ...                                                         [FAIL]
197     test_divide ...                                                      [FAIL]
198     test_multiply ...                                                    [FAIL]
199     test_subtract ...                                                    [FAIL]
200
201 ===============================================================================
202 [FAIL]
203 Traceback (most recent call last):
204   File &quot;/tmp/calculus/test/test_base_1.py&quot;, line 8, in test_add
205     self.assertEqual(result, 11)
206 twisted.trial.unittest.FailTest: not equal:
207 a = None
208 b = 11
209
210
211 calculus.test.test_base_1.CalculationTestCase.test_add
212 ===============================================================================
213 [FAIL]
214 Traceback (most recent call last):
215   File &quot;/tmp/calculus/test/test_base_1.py&quot;, line 23, in test_divide
216     self.assertEqual(result, 2)
217 twisted.trial.unittest.FailTest: not equal:
218 a = None
219 b = 2
220
221
222 calculus.test.test_base_1.CalculationTestCase.test_divide
223 ===============================================================================
224 [FAIL]
225 Traceback (most recent call last):
226   File &quot;/tmp/calculus/test/test_base_1.py&quot;, line 18, in test_multiply
227     self.assertEqual(result, 60)
228 twisted.trial.unittest.FailTest: not equal:
229 a = None
230 b = 60
231
232
233 calculus.test.test_base_1.CalculationTestCase.test_multiply
234 ===============================================================================
235 [FAIL]
236 Traceback (most recent call last):
237   File &quot;/tmp/calculus/test/test_base_1.py&quot;, line 13, in test_subtract
238     self.assertEqual(result, 4)
239 twisted.trial.unittest.FailTest: not equal:
240 a = None
241 b = 4
242
243
244 calculus.test.test_base_1.CalculationTestCase.test_subtract
245 -------------------------------------------------------------------------------
246 Ran 4 tests in 0.042s
247
248 FAILED (failures=4)
249 </pre>
250
251 <p>How to interpret this output? You get a list of the individual tests, each
252 followed by its result. By default, failures are printed at the end, but this
253 can be changed with the <code class="shell">-e</code> (or <code class="shell">--rterrors</code>) option.</p>
254
255 <p>One very useful thing in this output is the fully-qualified name of the
256 failed tests. This appears at the bottom of each =-delimited area of the
257 output. This allows you to copy and paste it to just run a single test you're
258 interested in. In our example, you could run <code class="shell">trial
259 calculus.test.test_base_1.CalculationTestCase.test_subtract</code> from the
260 shell.</p>
261
262 <p>Note that trial can use different reporters to modify its output. Run
263  <code class="shell">trial --help-reporters</code> to see a list of
264 reporters.</p>
265
266 <p>
267 The tests can be run by <code class="shell">trial</code> in multiple ways:
268 <ul>
269   <li><code class="shell">trial calculus</code>: run all the tests for the
270   calculus package.</li>
271
272   <li><code class="shell">trial calculus.test</code>: run using Python's
273   <code class="python">import</code> notation.</li>
274
275   <li><code class="shell">trial calculus.test.test_base_1</code>: as above, for
276   a specific test module. You can follow that logic by putting your class name
277   and even a method name to only run those specific tests.</li>
278
279   <li><a name="comment" shape="rect"/><code class="shell">trial
280   --testmodule=calculus/base_1.py</code>: use the <code class="python">test-case-name</code> comment in the first line of
281   <code class="py-filename">calculus/base_1.py</code> to find the tests.</li>
282
283   <li><code class="shell">trial calculus/test</code>: run all the tests in the
284   test directory (not recommended).</li>
285
286   <li><code class="shell">trial calculus/test/test_base_1.py</code>: run a
287   specific test file (not recommended).</li>
288 </ul>
289
290 The first 3 versions using full qualified names are strongly encouraged: they
291 are much more reliable and they allow you to easily be more selective in your
292 test runs.
293 </p>
294
295 <p>You'll notice that Trial create a <code class="shell">_trial_temp</code> directory in
296 the directory where you run the tests. This has a file called
297  <code class="shell">test.log</code> which contains the log output of the tests (created
298 using <code class="python">log.msg</code> or <code class="python">log.err</code> functions). Examine this file if you add
299 logging to your tests.</p>
300
301 <h2>Making the tests pass<a name="auto2"/></h2>
302
303 <p>Now that we have a working test framework in place, and our tests are
304 failing (as expected) we can go and try to implement the correct API. We'll do
305 that in a new version of the above base_1
306 module, <code class="py-filename">calculus/base_2.py</code>:</p>
307
308 <div class="py-listing"><pre><p class="py-linenumber"> 1
309  2
310  3
311  4
312  5
313  6
314  7
315  8
316  9
317 10
318 11
319 12
320 13
321 14
322 </p><span class="py-src-comment"># -*- test-case-name: calculus.test.test_base_2 -*-</span>
323
324 <span class="py-src-keyword">class</span> <span class="py-src-identifier">Calculation</span>(<span class="py-src-parameter">object</span>):
325     <span class="py-src-keyword">def</span> <span class="py-src-identifier">add</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
326         <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> + <span class="py-src-variable">b</span>
327
328     <span class="py-src-keyword">def</span> <span class="py-src-identifier">subtract</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
329         <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> - <span class="py-src-variable">b</span>
330
331     <span class="py-src-keyword">def</span> <span class="py-src-identifier">multiply</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
332         <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> * <span class="py-src-variable">b</span>
333
334     <span class="py-src-keyword">def</span> <span class="py-src-identifier">divide</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
335         <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> / <span class="py-src-variable">b</span>
336 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/base_2.py"><span class="filename">listings/trial/calculus/base_2.py</span></a></div></div>
337
338 <p>We'll also create a new version of test_base_1 which imports and tests this
339 new implementation,
340 in <code class="py-filename">calculus/test_base_2.py</code>:</p>
341
342 <p><div class="py-listing"><pre><p class="py-linenumber"> 1
343  2
344  3
345  4
346  5
347  6
348  7
349  8
350  9
351 10
352 11
353 12
354 13
355 14
356 15
357 16
358 17
359 18
360 19
361 20
362 21
363 22
364 23
365 24
366 25
367 26
368 27
369 28
370 29
371 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">base_2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Calculation</span>
372 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">trial</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">unittest</span>
373
374
375
376 <span class="py-src-keyword">class</span> <span class="py-src-identifier">CalculationTestCase</span>(<span class="py-src-parameter">unittest</span>.<span class="py-src-parameter">TestCase</span>):
377
378     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_add</span>(<span class="py-src-parameter">self</span>):
379         <span class="py-src-variable">calc</span> = <span class="py-src-variable">Calculation</span>()
380         <span class="py-src-variable">result</span> = <span class="py-src-variable">calc</span>.<span class="py-src-variable">add</span>(<span class="py-src-number">3</span>, <span class="py-src-number">8</span>)
381         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">result</span>, <span class="py-src-number">11</span>)
382
383
384     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_subtract</span>(<span class="py-src-parameter">self</span>):
385         <span class="py-src-variable">calc</span> = <span class="py-src-variable">Calculation</span>()
386         <span class="py-src-variable">result</span> = <span class="py-src-variable">calc</span>.<span class="py-src-variable">subtract</span>(<span class="py-src-number">7</span>, <span class="py-src-number">3</span>)
387         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">result</span>, <span class="py-src-number">4</span>)
388
389
390     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_multiply</span>(<span class="py-src-parameter">self</span>):
391         <span class="py-src-variable">calc</span> = <span class="py-src-variable">Calculation</span>()
392         <span class="py-src-variable">result</span> = <span class="py-src-variable">calc</span>.<span class="py-src-variable">multiply</span>(<span class="py-src-number">12</span>, <span class="py-src-number">5</span>)
393         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">result</span>, <span class="py-src-number">60</span>)
394
395
396     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_divide</span>(<span class="py-src-parameter">self</span>):
397         <span class="py-src-variable">calc</span> = <span class="py-src-variable">Calculation</span>()
398         <span class="py-src-variable">result</span> = <span class="py-src-variable">calc</span>.<span class="py-src-variable">divide</span>(<span class="py-src-number">12</span>, <span class="py-src-number">5</span>)
399         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">result</span>, <span class="py-src-number">2</span>)
400 </pre><div class="caption">test_base_2 - <a href="listings/trial/calculus/test/test_base_2.py"><span class="filename">listings/trial/calculus/test/test_base_2.py</span></a></div></div> is a copy of test_base_1, but with the import changed. Run <code class="shell">trial</code> again as above, and your tests should now pass:</p>
401
402 <pre class="shell" xml:space="preserve">
403 $ trial calculus.test.test_base_2
404
405 Running 4 tests.
406 calculus.test.test_base
407   CalculationTestCase
408     test_add ...                                                           [OK]
409     test_divide ...                                                        [OK]
410     test_multiply ...                                                      [OK]
411     test_subtract ...                                                      [OK]
412
413 -------------------------------------------------------------------------------
414 Ran 4 tests in 0.067s
415
416 PASSED (successes=4)
417 </pre>
418
419 <h3>Factoring out common test logic<a name="auto3"/></h3>
420
421 <p>You'll notice that our test file contains redundant code. Let's get rid
422 of that. Python's unit testing framework allows your test class to define a
423  <code class="python">setUp</code> method that is called before
424  <em>each</em> test method in the class. This allows you to add attributes
425 to <code class="python">self</code> that can be used in tests
426 methods. We'll also add a parameterized test method to further simplify the
427 code.</p>
428
429 <p>Note that a test class may also provide the counterpart of <code class="python">setUp</code>, named <code class="python">tearDown</code>,
430 which will be called after <em>each</em> test (whether successful or
431 not). <code class="python">tearDown</code> is mainly used for post-test
432 cleanup purposes. We will not use <code class="python">tearDown</code>
433 until later.</p>
434
435 <p>Create <code class="py-filename">calculus/test/test_base_2b.py</code> as
436 follows:</p>
437
438 <div class="py-listing"><pre><p class="py-linenumber"> 1
439  2
440  3
441  4
442  5
443  6
444  7
445  8
446  9
447 10
448 11
449 12
450 13
451 14
452 15
453 16
454 17
455 18
456 19
457 20
458 21
459 22
460 23
461 24
462 25
463 26
464 27
465 28
466 29
467 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">base_2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Calculation</span>
468 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">trial</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">unittest</span>
469
470
471
472 <span class="py-src-keyword">class</span> <span class="py-src-identifier">CalculationTestCase</span>(<span class="py-src-parameter">unittest</span>.<span class="py-src-parameter">TestCase</span>):
473     <span class="py-src-keyword">def</span> <span class="py-src-identifier">setUp</span>(<span class="py-src-parameter">self</span>):
474         <span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span> = <span class="py-src-variable">Calculation</span>()
475
476
477     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_test</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">operation</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>, <span class="py-src-parameter">expected</span>):
478         <span class="py-src-variable">result</span> = <span class="py-src-variable">operation</span>(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
479         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">expected</span>)
480
481
482     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_add</span>(<span class="py-src-parameter">self</span>):
483         <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>.<span class="py-src-variable">add</span>, <span class="py-src-number">3</span>, <span class="py-src-number">8</span>, <span class="py-src-number">11</span>)
484
485
486     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_subtract</span>(<span class="py-src-parameter">self</span>):
487         <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>.<span class="py-src-variable">subtract</span>, <span class="py-src-number">7</span>, <span class="py-src-number">3</span>, <span class="py-src-number">4</span>)
488
489
490     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_multiply</span>(<span class="py-src-parameter">self</span>):
491         <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>.<span class="py-src-variable">multiply</span>, <span class="py-src-number">6</span>, <span class="py-src-number">9</span>, <span class="py-src-number">54</span>)
492
493
494     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_divide</span>(<span class="py-src-parameter">self</span>):
495         <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>.<span class="py-src-variable">divide</span>, <span class="py-src-number">12</span>, <span class="py-src-number">5</span>, <span class="py-src-number">2</span>)
496 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/test/test_base_2b.py"><span class="filename">listings/trial/calculus/test/test_base_2b.py</span></a></div></div>
497
498 <p>Much cleaner, no?</p>
499
500 <p>We'll now add some additional error tests. Testing just for successful
501 use of the API is generally not enough, especially if you expect your code
502 to be used by others. Let's make sure the <code class="python">Calculation</code> class raises exceptions if someone tries
503 to call its methods with arguments that cannot be converted to
504 integers.</p>
505
506 <p>We arrive at <code class="py-filename">calculus/test/test_base_3.py</code>:</p>
507
508 <div class="py-listing"><pre><p class="py-linenumber"> 1
509  2
510  3
511  4
512  5
513  6
514  7
515  8
516  9
517 10
518 11
519 12
520 13
521 14
522 15
523 16
524 17
525 18
526 19
527 20
528 21
529 22
530 23
531 24
532 25
533 26
534 27
535 28
536 29
537 30
538 31
539 32
540 33
541 34
542 35
543 36
544 37
545 38
546 39
547 40
548 41
549 42
550 43
551 44
552 45
553 46
554 47
555 48
556 49
557 50
558 51
559 52
560 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">base_3</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Calculation</span>
561 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">trial</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">unittest</span>
562
563
564
565 <span class="py-src-keyword">class</span> <span class="py-src-identifier">CalculationTestCase</span>(<span class="py-src-parameter">unittest</span>.<span class="py-src-parameter">TestCase</span>):
566     <span class="py-src-keyword">def</span> <span class="py-src-identifier">setUp</span>(<span class="py-src-parameter">self</span>):
567         <span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span> = <span class="py-src-variable">Calculation</span>()
568
569
570     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_test</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">operation</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>, <span class="py-src-parameter">expected</span>):
571         <span class="py-src-variable">result</span> = <span class="py-src-variable">operation</span>(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
572         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">result</span>, <span class="py-src-variable">expected</span>)
573
574
575     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_test_error</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">operation</span>):
576         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertRaises</span>(<span class="py-src-variable">TypeError</span>, <span class="py-src-variable">operation</span>, <span class="py-src-string">&quot;foo&quot;</span>, <span class="py-src-number">2</span>)
577         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertRaises</span>(<span class="py-src-variable">TypeError</span>, <span class="py-src-variable">operation</span>, <span class="py-src-string">&quot;bar&quot;</span>, <span class="py-src-string">&quot;egg&quot;</span>)
578         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertRaises</span>(<span class="py-src-variable">TypeError</span>, <span class="py-src-variable">operation</span>, [<span class="py-src-number">3</span>], [<span class="py-src-number">8</span>, <span class="py-src-number">2</span>])
579         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertRaises</span>(<span class="py-src-variable">TypeError</span>, <span class="py-src-variable">operation</span>, {<span class="py-src-string">&quot;e&quot;</span>: <span class="py-src-number">3</span>}, {<span class="py-src-string">&quot;r&quot;</span>: <span class="py-src-string">&quot;t&quot;</span>})
580
581
582     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_add</span>(<span class="py-src-parameter">self</span>):
583         <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>.<span class="py-src-variable">add</span>, <span class="py-src-number">3</span>, <span class="py-src-number">8</span>, <span class="py-src-number">11</span>)
584
585
586     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_subtract</span>(<span class="py-src-parameter">self</span>):
587         <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>.<span class="py-src-variable">subtract</span>, <span class="py-src-number">7</span>, <span class="py-src-number">3</span>, <span class="py-src-number">4</span>)
588
589
590     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_multiply</span>(<span class="py-src-parameter">self</span>):
591         <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>.<span class="py-src-variable">multiply</span>, <span class="py-src-number">6</span>, <span class="py-src-number">9</span>, <span class="py-src-number">54</span>)
592
593
594     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_divide</span>(<span class="py-src-parameter">self</span>):
595         <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>.<span class="py-src-variable">divide</span>, <span class="py-src-number">12</span>, <span class="py-src-number">5</span>, <span class="py-src-number">2</span>)
596
597
598     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_errorAdd</span>(<span class="py-src-parameter">self</span>):
599         <span class="py-src-variable">self</span>.<span class="py-src-variable">_test_error</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>.<span class="py-src-variable">add</span>)
600
601
602     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_errorSubtract</span>(<span class="py-src-parameter">self</span>):
603         <span class="py-src-variable">self</span>.<span class="py-src-variable">_test_error</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>.<span class="py-src-variable">subtract</span>)
604
605
606     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_errorMultiply</span>(<span class="py-src-parameter">self</span>):
607         <span class="py-src-variable">self</span>.<span class="py-src-variable">_test_error</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>.<span class="py-src-variable">multiply</span>)
608
609
610     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_errorDivide</span>(<span class="py-src-parameter">self</span>):
611         <span class="py-src-variable">self</span>.<span class="py-src-variable">_test_error</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>.<span class="py-src-variable">divide</span>)
612 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/test/test_base_3.py"><span class="filename">listings/trial/calculus/test/test_base_3.py</span></a></div></div>
613
614 <p>We've added four new tests and one general-purpose function, <code class="python">_test_error</code>. This function uses the <code class="python">assertRaises</code> method, which takes an exception class,
615 a function to run and its arguments, and checks that calling the function
616 on the arguments does indeed raise the given exception.</p>
617
618 <p>If you run the above, you'll see that not all tests fail. In Python it's
619 often valid to add and multiply objects of different and even differing
620 types, so the code in the add and mutiply tests does not raise an exception
621 and those tests therefore fail. So let's add explicit type conversion to
622 our API class. This brings us to <code class="py-filename">calculus/base_3.py</code>:</p>
623
624 <div class="py-listing"><pre><p class="py-linenumber"> 1
625  2
626  3
627  4
628  5
629  6
630  7
631  8
632  9
633 10
634 11
635 12
636 13
637 14
638 15
639 16
640 17
641 18
642 19
643 20
644 21
645 22
646 23
647 24
648 </p><span class="py-src-comment"># -*- test-case-name: calculus.test.test_base_3 -*-</span>
649
650 <span class="py-src-keyword">class</span> <span class="py-src-identifier">Calculation</span>(<span class="py-src-parameter">object</span>):
651     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_make_ints</span>(<span class="py-src-parameter">self</span>, *<span class="py-src-parameter">args</span>):
652         <span class="py-src-keyword">try</span>:
653             <span class="py-src-keyword">return</span> <span class="py-src-variable">map</span>(<span class="py-src-variable">int</span>, <span class="py-src-variable">args</span>)
654         <span class="py-src-keyword">except</span> <span class="py-src-variable">ValueError</span>:
655             <span class="py-src-keyword">raise</span> <span class="py-src-variable">TypeError</span>(<span class="py-src-string">&quot;Couldn't coerce arguments to integers: %s&quot;</span> % <span class="py-src-variable">args</span>)
656
657     <span class="py-src-keyword">def</span> <span class="py-src-identifier">add</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
658         <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">_make_ints</span>(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
659         <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> + <span class="py-src-variable">b</span>
660
661     <span class="py-src-keyword">def</span> <span class="py-src-identifier">subtract</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
662         <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">_make_ints</span>(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
663         <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> - <span class="py-src-variable">b</span>
664
665     <span class="py-src-keyword">def</span> <span class="py-src-identifier">multiply</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
666         <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">_make_ints</span>(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
667         <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> * <span class="py-src-variable">b</span>
668
669     <span class="py-src-keyword">def</span> <span class="py-src-identifier">divide</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
670         <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">_make_ints</span>(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
671         <span class="py-src-keyword">return</span> <span class="py-src-variable">a</span> / <span class="py-src-variable">b</span>
672 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/base_3.py"><span class="filename">listings/trial/calculus/base_3.py</span></a></div></div>
673
674 <p>Here the <code class="python">_make_ints</code> helper function tries to
675 convert a list into a list of equivalent integers, and raises a <code class="python">TypeError</code> in case the conversion goes wrong.
676
677 <div class="note"><strong>Note: </strong>The <code class="python">int</code> conversion can also
678 raise a <code class="python">TypeError</code> if passed something of the
679 wrong type, such as a list. We'll just let that exception go by as <code class="python">TypeError</code> is already what we want in case something
680 goes wrong.</div></p>
681
682
683 <a name="twisted" shape="rect"/>
684 <h2>Twisted specific testing<a name="auto4"/></h2>
685
686 <p>Up to this point we've been doing fairly standard Python unit testing.
687 With only a few cosmetic changes (most importantly, directly importing
688  <code class="python">unittest</code> instead of using Twisted's <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.trial.unittest.html" title="twisted.trial.unittest">unittest</a></code> version) we could make the
689 above tests run using Python's standard library unit testing framework.</p>
690
691 <p>Here we will assume a basic familiarity with Twisted's network I/O, timing,
692 and Deferred APIs.  If you haven't already read them, you should read the
693 documentation on <a href="servers.html" shape="rect">Writing
694 Servers</a>, <a href="clients.html" shape="rect">Writing Clients</a>,
695 and <a href="defer.html" shape="rect">Deferreds</a>.</p>
696
697 <p>Now we'll get to the real point of this tutorial and take advantage of
698 Trial to test Twisted code.</p>
699
700 <h2>Testing a protocol<a name="auto5"/></h2>
701
702 <p>We'll now create a custom protocol to invoke our class from within a
703 telnet-like session. We'll remotely call commands with arguments and read back
704 the response. The goal will be to test our network code without creating
705 sockets.</p>
706
707 <h3>Creating and testing the server<a name="auto6"/></h3>
708
709 <p>First we'll write the tests, and then explain what they do.  The first
710 version of the remote test code is:</p>
711
712 <div class="py-listing"><pre><p class="py-linenumber"> 1
713  2
714  3
715  4
716  5
717  6
718  7
719  8
720  9
721 10
722 11
723 12
724 13
725 14
726 15
727 16
728 17
729 18
730 19
731 20
732 21
733 22
734 23
735 24
736 25
737 26
738 27
739 28
740 29
741 30
742 31
743 32
744 33
745 34
746 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">remote_1</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">RemoteCalculationFactory</span>
747 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">trial</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">unittest</span>
748 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">test</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">proto_helpers</span>
749
750
751
752 <span class="py-src-keyword">class</span> <span class="py-src-identifier">RemoteCalculationTestCase</span>(<span class="py-src-parameter">unittest</span>.<span class="py-src-parameter">TestCase</span>):
753     <span class="py-src-keyword">def</span> <span class="py-src-identifier">setUp</span>(<span class="py-src-parameter">self</span>):
754         <span class="py-src-variable">factory</span> = <span class="py-src-variable">RemoteCalculationFactory</span>()
755         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span> = <span class="py-src-variable">factory</span>.<span class="py-src-variable">buildProtocol</span>((<span class="py-src-string">'127.0.0.1'</span>, <span class="py-src-number">0</span>))
756         <span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span> = <span class="py-src-variable">proto_helpers</span>.<span class="py-src-variable">StringTransport</span>()
757         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">makeConnection</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>)
758
759
760     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_test</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">operation</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>, <span class="py-src-parameter">expected</span>):
761         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">dataReceived</span>(<span class="py-src-string">'%s %d %d\r\n'</span> % (<span class="py-src-variable">operation</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>))
762         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">int</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">value</span>()), <span class="py-src-variable">expected</span>)
763
764
765     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_add</span>(<span class="py-src-parameter">self</span>):
766         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'add'</span>, <span class="py-src-number">7</span>, <span class="py-src-number">6</span>, <span class="py-src-number">13</span>)
767
768
769     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_subtract</span>(<span class="py-src-parameter">self</span>):
770         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'subtract'</span>, <span class="py-src-number">82</span>, <span class="py-src-number">78</span>, <span class="py-src-number">4</span>)
771
772
773     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_multiply</span>(<span class="py-src-parameter">self</span>):
774         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'multiply'</span>, <span class="py-src-number">2</span>, <span class="py-src-number">8</span>, <span class="py-src-number">16</span>)
775
776
777     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_divide</span>(<span class="py-src-parameter">self</span>):
778         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'divide'</span>, <span class="py-src-number">14</span>, <span class="py-src-number">3</span>, <span class="py-src-number">4</span>)
779 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/test/test_remote_1.py"><span class="filename">listings/trial/calculus/test/test_remote_1.py</span></a></div></div>
780
781 <p>To fully understand this client, it helps a lot to be comfortable with
782 the Factory/Protocol/Transport pattern used in Twisted.</p>
783
784 <p>We first create a protocol factory object. Note that we have yet to see
785 the <code class="python">RemoteCalculationFactory</code> class. It is in
786  <code class="py-filename">calculus/remote_1.py</code> below. We
787 call <code class="python">buildProtocol</code> to ask the factory to build us a
788 protocol object that knows how to talk to our server.  We then make a fake
789 network transport, an instance of <code class="python">twisted.test.proto_helpers.StringTransport</code>
790 class (note that test packages are generally not part of Twisted's public API;
791 <code class="python">twisted.test.proto_helpers</code> is an exception).  This fake
792 transport is the key to the communications. It is used to emulate a network
793 connection without a network. The address and port passed to <code>buildProtocol</code>
794 are typically used by the factory to choose to immediately deny remote connections; since we're using a fake transport, we can choose any value that will be acceptable to the factory. In this case the factory just ignores the address, so we don't need to pick anything in particular.</p>
795
796 <p>Testing protocols without the use of real network connections is both simple and recommended when testing Twisted
797 code.  Even though there are many tests in Twisted that use the network,
798 most good tests don't. The problem with unit tests and networking is that
799 networks aren't reliable. We cannot know that they will exhibit reasonable
800 behavior all the time. This creates intermittent test failures due to
801 network vagaries. Right now we're trying to test our Twisted code, not
802 network reliability.  By setting up and using a fake transport, we can
803 write 100% reliable tests. We can also test network failures in a deterministic manner, another important part of your complete test suite.</p>
804
805 <p>The final key to understanding this client code is the <code class="python">_test</code> method. The call to <code class="python">dataReceived</code> simulates data arriving on the network
806 transport. But where does it arrive? It's handed to the <code class="python">lineReceived</code> method of the protocol instance (in
807  <code class="py-filename">calculus/remote_1.py</code> below). So the client
808 is essentially tricking the server into thinking it has received the
809 operation and the arguments over the network. The server (once again, see
810 below) hands the work off to its <code class="python">CalculationProxy</code> object which in turn hands it to its
811  <code class="python">Calculation</code> instance. The result is written
812 back via <code class="python">sendLine</code> (into the fake string
813 transport object), and is then immediately available to the client, who
814 fetches it with <code class="python">tr.value()</code> and checks that it
815 has the expected value. So there's quite a lot going on behind the scenes
816 in the two-line <code class="python">_test</code> method above.</p>
817
818 <p><em>Finally</em>, let's see the implementation of this protocol. Put the
819 following into <code class="py-filename">calculus/remote_1.py</code>:</p>
820
821 <div class="py-listing"><pre><p class="py-linenumber"> 1
822  2
823  3
824  4
825  5
826  6
827  7
828  8
829  9
830 10
831 11
832 12
833 13
834 14
835 15
836 16
837 17
838 18
839 19
840 20
841 21
842 22
843 23
844 24
845 25
846 26
847 27
848 28
849 29
850 30
851 31
852 32
853 33
854 34
855 35
856 36
857 37
858 38
859 39
860 40
861 41
862 42
863 43
864 44
865 45
866 46
867 47
868 </p><span class="py-src-comment"># -*- test-case-name: calculus.test.test_remote_1 -*-</span>
869
870 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">protocols</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">basic</span>
871 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">protocol</span>
872 <span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">base_3</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Calculation</span>
873
874
875
876 <span class="py-src-keyword">class</span> <span class="py-src-identifier">CalculationProxy</span>(<span class="py-src-parameter">object</span>):
877     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>):
878         <span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span> = <span class="py-src-variable">Calculation</span>()
879         <span class="py-src-keyword">for</span> <span class="py-src-variable">m</span> <span class="py-src-keyword">in</span> [<span class="py-src-string">'add'</span>, <span class="py-src-string">'subtract'</span>, <span class="py-src-string">'multiply'</span>, <span class="py-src-string">'divide'</span>]:
880             <span class="py-src-variable">setattr</span>(<span class="py-src-variable">self</span>, <span class="py-src-string">'remote_%s'</span> % <span class="py-src-variable">m</span>, <span class="py-src-variable">getattr</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>, <span class="py-src-variable">m</span>))
881
882
883
884 <span class="py-src-keyword">class</span> <span class="py-src-identifier">RemoteCalculationProtocol</span>(<span class="py-src-parameter">basic</span>.<span class="py-src-parameter">LineReceiver</span>):
885     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>):
886         <span class="py-src-variable">self</span>.<span class="py-src-variable">proxy</span> = <span class="py-src-variable">CalculationProxy</span>()
887
888
889     <span class="py-src-keyword">def</span> <span class="py-src-identifier">lineReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">line</span>):
890         <span class="py-src-variable">op</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span> = <span class="py-src-variable">line</span>.<span class="py-src-variable">split</span>()
891         <span class="py-src-variable">a</span> = <span class="py-src-variable">int</span>(<span class="py-src-variable">a</span>)
892         <span class="py-src-variable">b</span> = <span class="py-src-variable">int</span>(<span class="py-src-variable">b</span>)
893         <span class="py-src-variable">op</span> = <span class="py-src-variable">getattr</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">proxy</span>, <span class="py-src-string">'remote_%s'</span> % (<span class="py-src-variable">op</span>,))
894         <span class="py-src-variable">result</span> = <span class="py-src-variable">op</span>(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
895         <span class="py-src-variable">self</span>.<span class="py-src-variable">sendLine</span>(<span class="py-src-variable">str</span>(<span class="py-src-variable">result</span>))
896
897
898
899 <span class="py-src-keyword">class</span> <span class="py-src-identifier">RemoteCalculationFactory</span>(<span class="py-src-parameter">protocol</span>.<span class="py-src-parameter">Factory</span>):
900     <span class="py-src-variable">protocol</span> = <span class="py-src-variable">RemoteCalculationProtocol</span>
901
902
903
904 <span class="py-src-keyword">def</span> <span class="py-src-identifier">main</span>():
905     <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
906     <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">log</span>
907     <span class="py-src-keyword">import</span> <span class="py-src-variable">sys</span>
908     <span class="py-src-variable">log</span>.<span class="py-src-variable">startLogging</span>(<span class="py-src-variable">sys</span>.<span class="py-src-variable">stdout</span>)
909     <span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">0</span>, <span class="py-src-variable">RemoteCalculationFactory</span>())
910     <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
911
912
913 <span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">&quot;__main__&quot;</span>:
914     <span class="py-src-variable">main</span>()
915 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/remote_1.py"><span class="filename">listings/trial/calculus/remote_1.py</span></a></div></div>
916
917 <p>As mentioned, this server creates a protocol that inherits from <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.protocols.basic.LineReceiver.html" title="twisted.protocols.basic.LineReceiver">basic.LineReceiver</a></code>, and then a
918 factory that uses it as protocol. The only trick is the <code class="python">CalculationProxy</code> object, which calls <code class="python">Calculation</code> methods through <code class="python">remote_*</code> methods. This pattern is used frequently in
919 Twisted, because it is very explicit about what methods you are making
920 accessible.</p>
921
922 <p>If you run this test (<code class="shell">trial
923 calculus.test.test_remote_1</code>), everything should be fine. You can also
924 run a server to test it with a telnet client. To do that, call <code class="shell">python calculus/remote_1.py</code>. You should have the following output:</p>
925
926 <pre class="shell" xml:space="preserve">
927 2008-04-25 10:53:27+0200 [-] Log opened.
928 2008-04-25 10:53:27+0200 [-] __main__.RemoteCalculationFactory starting on 46194
929 2008-04-25 10:53:27+0200 [-] Starting factory &lt;__main__.RemoteCalculationFactory instance at 0x846a0cc&gt;
930 </pre>
931
932 <p>46194 is replaced by a random port. You can then call telnet on it:</p>
933 <pre xml:space="preserve">
934 $ telnet localhost 46194
935 Trying 127.0.0.1...
936 Connected to localhost.
937 Escape character is '^]'.
938 add 4123 9423
939 13546
940 </pre>
941
942 <p>It works!</p>
943
944 <h3>Creating and testing the client<a name="auto7"/></h3>
945
946 <p>Of course, what we build is not particulary useful for now : we'll now build
947 a client to our server, to be able to use it inside a Python program. And it
948 will serve our next purpose.</p>
949
950 <p>Create <code class="py-filename">calculus/test/test_client_1.py</code>:</p>
951
952 <div class="py-listing"><pre><p class="py-linenumber"> 1
953  2
954  3
955  4
956  5
957  6
958  7
959  8
960  9
961 10
962 11
963 12
964 13
965 14
966 15
967 16
968 17
969 18
970 19
971 20
972 21
973 22
974 23
975 24
976 25
977 26
978 27
979 28
980 29
981 30
982 31
983 32
984 33
985 34
986 35
987 36
988 37
989 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">client_1</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">RemoteCalculationClient</span>
990 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">trial</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">unittest</span>
991 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">test</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">proto_helpers</span>
992
993
994
995 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ClientCalculationTestCase</span>(<span class="py-src-parameter">unittest</span>.<span class="py-src-parameter">TestCase</span>):
996     <span class="py-src-keyword">def</span> <span class="py-src-identifier">setUp</span>(<span class="py-src-parameter">self</span>):
997         <span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span> = <span class="py-src-variable">proto_helpers</span>.<span class="py-src-variable">StringTransport</span>()
998         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span> = <span class="py-src-variable">RemoteCalculationClient</span>()
999         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">makeConnection</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>)
1000
1001
1002     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_test</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">operation</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>, <span class="py-src-parameter">expected</span>):
1003         <span class="py-src-variable">d</span> = <span class="py-src-variable">getattr</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>, <span class="py-src-variable">operation</span>)(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1004         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">value</span>(), <span class="py-src-string">'%s %d %d\r\n'</span> % (<span class="py-src-variable">operation</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>))
1005         <span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">clear</span>()
1006         <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>, <span class="py-src-variable">expected</span>)
1007         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">dataReceived</span>(<span class="py-src-string">&quot;%d\r\n&quot;</span> % (<span class="py-src-variable">expected</span>,))
1008         <span class="py-src-keyword">return</span> <span class="py-src-variable">d</span>
1009
1010
1011     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_add</span>(<span class="py-src-parameter">self</span>):
1012         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'add'</span>, <span class="py-src-number">7</span>, <span class="py-src-number">6</span>, <span class="py-src-number">13</span>)
1013
1014
1015     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_subtract</span>(<span class="py-src-parameter">self</span>):
1016         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'subtract'</span>, <span class="py-src-number">82</span>, <span class="py-src-number">78</span>, <span class="py-src-number">4</span>)
1017
1018
1019     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_multiply</span>(<span class="py-src-parameter">self</span>):
1020         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'multiply'</span>, <span class="py-src-number">2</span>, <span class="py-src-number">8</span>, <span class="py-src-number">16</span>)
1021
1022
1023     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_divide</span>(<span class="py-src-parameter">self</span>):
1024         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'divide'</span>, <span class="py-src-number">14</span>, <span class="py-src-number">3</span>, <span class="py-src-number">4</span>)
1025 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/test/test_client_1.py"><span class="filename">listings/trial/calculus/test/test_client_1.py</span></a></div></div>
1026
1027 <p>It's really symmetric to the server test cases. The only tricky part is
1028 that we don't use a client factory. We're lazy, and it's not very useful in
1029 the client part, so we instantiate the protocol directly.</p>
1030
1031 <p>Incidentally, we have introduced a very important concept here: the tests
1032 now return a Deferred object, and the assertion is done in a callback. The
1033 important thing to do here is to <strong>not forget to return the
1034 Deferred</strong>. If you do, your tests will pass even if nothing is asserted.
1035 That's also why it's important to make tests fail first: if your tests pass
1036 whereas you know they shouldn't, there is a problem in your tests.</p>
1037
1038 <p>We'll now add the remote client class to produce <code class="py-filename">calculus/client_1.py</code>:</p>
1039
1040 <div class="py-listing"><pre><p class="py-linenumber"> 1
1041  2
1042  3
1043  4
1044  5
1045  6
1046  7
1047  8
1048  9
1049 10
1050 11
1051 12
1052 13
1053 14
1054 15
1055 16
1056 17
1057 18
1058 19
1059 20
1060 21
1061 22
1062 23
1063 24
1064 25
1065 26
1066 27
1067 28
1068 29
1069 30
1070 31
1071 32
1072 33
1073 34
1074 35
1075 36
1076 37
1077 38
1078 39
1079 </p><span class="py-src-comment"># -*- test-case-name: calculus.test.test_client_1 -*-</span>
1080
1081 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">protocols</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">basic</span>
1082 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
1083
1084
1085
1086 <span class="py-src-keyword">class</span> <span class="py-src-identifier">RemoteCalculationClient</span>(<span class="py-src-parameter">basic</span>.<span class="py-src-parameter">LineReceiver</span>):
1087     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>):
1088         <span class="py-src-variable">self</span>.<span class="py-src-variable">results</span> = []
1089
1090
1091     <span class="py-src-keyword">def</span> <span class="py-src-identifier">lineReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">line</span>):
1092         <span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">results</span>.<span class="py-src-variable">pop</span>(<span class="py-src-number">0</span>)
1093         <span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-variable">int</span>(<span class="py-src-variable">line</span>))
1094
1095
1096     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_sendOperation</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">op</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1097         <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
1098         <span class="py-src-variable">self</span>.<span class="py-src-variable">results</span>.<span class="py-src-variable">append</span>(<span class="py-src-variable">d</span>)
1099         <span class="py-src-variable">line</span> = <span class="py-src-string">&quot;%s %d %d&quot;</span> % (<span class="py-src-variable">op</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1100         <span class="py-src-variable">self</span>.<span class="py-src-variable">sendLine</span>(<span class="py-src-variable">line</span>)
1101         <span class="py-src-keyword">return</span> <span class="py-src-variable">d</span>
1102
1103
1104     <span class="py-src-keyword">def</span> <span class="py-src-identifier">add</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1105         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_sendOperation</span>(<span class="py-src-string">&quot;add&quot;</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1106
1107
1108     <span class="py-src-keyword">def</span> <span class="py-src-identifier">subtract</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1109         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_sendOperation</span>(<span class="py-src-string">&quot;subtract&quot;</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1110
1111
1112     <span class="py-src-keyword">def</span> <span class="py-src-identifier">multiply</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1113         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_sendOperation</span>(<span class="py-src-string">&quot;multiply&quot;</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1114
1115
1116     <span class="py-src-keyword">def</span> <span class="py-src-identifier">divide</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1117         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_sendOperation</span>(<span class="py-src-string">&quot;divide&quot;</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1118 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/client_1.py"><span class="filename">listings/trial/calculus/client_1.py</span></a></div></div>
1119
1120
1121 <h2>More good practices<a name="auto8"/></h2>
1122
1123 <h3>Testing scheduling<a name="auto9"/></h3>
1124
1125 <p>When testing code that involves the passage of time, waiting e.g. for a two hour timeout to occur in a test is not very realistic. Twisted provides a solution to this, the <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.internet.task.Clock.html" title="twisted.internet.task.Clock">Clock</a></code> class that allows one to simulate the passage of time.</p>
1126
1127 <p>As an example we'll test the code for client request timeout: since our client
1128 uses TCP it can hang for a long time (firewall, connectivity problems, etc...).
1129 So generally we need to implement timeouts on the client side. Basically it's
1130 just that we send a request, don't receive a response and expect a timeout error
1131 to be triggered after a certain duration.
1132 </p>
1133
1134 <div class="py-listing"><pre><p class="py-linenumber"> 1
1135  2
1136  3
1137  4
1138  5
1139  6
1140  7
1141  8
1142  9
1143 10
1144 11
1145 12
1146 13
1147 14
1148 15
1149 16
1150 17
1151 18
1152 19
1153 20
1154 21
1155 22
1156 23
1157 24
1158 25
1159 26
1160 27
1161 28
1162 29
1163 30
1164 31
1165 32
1166 33
1167 34
1168 35
1169 36
1170 37
1171 38
1172 39
1173 40
1174 41
1175 42
1176 43
1177 44
1178 45
1179 46
1180 47
1181 48
1182 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">client_2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">RemoteCalculationClient</span>, <span class="py-src-variable">ClientTimeoutError</span>
1183
1184 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">task</span>
1185 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">trial</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">unittest</span>
1186 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">test</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">proto_helpers</span>
1187
1188
1189
1190 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ClientCalculationTestCase</span>(<span class="py-src-parameter">unittest</span>.<span class="py-src-parameter">TestCase</span>):
1191     <span class="py-src-keyword">def</span> <span class="py-src-identifier">setUp</span>(<span class="py-src-parameter">self</span>):
1192         <span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span> = <span class="py-src-variable">proto_helpers</span>.<span class="py-src-variable">StringTransportWithDisconnection</span>()
1193         <span class="py-src-variable">self</span>.<span class="py-src-variable">clock</span> = <span class="py-src-variable">task</span>.<span class="py-src-variable">Clock</span>()
1194         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span> = <span class="py-src-variable">RemoteCalculationClient</span>()
1195         <span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>
1196         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">callLater</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">clock</span>.<span class="py-src-variable">callLater</span>
1197         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">makeConnection</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>)
1198
1199
1200     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_test</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">operation</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>, <span class="py-src-parameter">expected</span>):
1201         <span class="py-src-variable">d</span> = <span class="py-src-variable">getattr</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>, <span class="py-src-variable">operation</span>)(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1202         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">value</span>(), <span class="py-src-string">'%s %d %d\r\n'</span> % (<span class="py-src-variable">operation</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>))
1203         <span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">clear</span>()
1204         <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>, <span class="py-src-variable">expected</span>)
1205         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">dataReceived</span>(<span class="py-src-string">&quot;%d\r\n&quot;</span> % (<span class="py-src-variable">expected</span>,))
1206         <span class="py-src-keyword">return</span> <span class="py-src-variable">d</span>
1207
1208
1209     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_add</span>(<span class="py-src-parameter">self</span>):
1210         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'add'</span>, <span class="py-src-number">7</span>, <span class="py-src-number">6</span>, <span class="py-src-number">13</span>)
1211
1212
1213     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_subtract</span>(<span class="py-src-parameter">self</span>):
1214         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'subtract'</span>, <span class="py-src-number">82</span>, <span class="py-src-number">78</span>, <span class="py-src-number">4</span>)
1215
1216
1217     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_multiply</span>(<span class="py-src-parameter">self</span>):
1218         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'multiply'</span>, <span class="py-src-number">2</span>, <span class="py-src-number">8</span>, <span class="py-src-number">16</span>)
1219
1220
1221     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_divide</span>(<span class="py-src-parameter">self</span>):
1222         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'divide'</span>, <span class="py-src-number">14</span>, <span class="py-src-number">3</span>, <span class="py-src-number">4</span>)
1223
1224
1225     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_timeout</span>(<span class="py-src-parameter">self</span>):
1226         <span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">add</span>(<span class="py-src-number">9</span>, <span class="py-src-number">4</span>)
1227         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">value</span>(), <span class="py-src-string">'add 9 4\r\n'</span>)
1228         <span class="py-src-variable">self</span>.<span class="py-src-variable">clock</span>.<span class="py-src-variable">advance</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">timeOut</span>)
1229         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">assertFailure</span>(<span class="py-src-variable">d</span>, <span class="py-src-variable">ClientTimeoutError</span>)
1230 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/test/test_client_2.py"><span class="filename">listings/trial/calculus/test/test_client_2.py</span></a></div></div>
1231
1232 <p>What happens here? We instantiate our protocol as usual, the only trick
1233 is to create the clock, and assign <code class="python">proto.callLater</code> to
1234  <code class="python">clock.callLater</code>. Thus, every callLater calls in the protocol
1235 will finish before <code class="python">clock.advance()</code> returns.</p>
1236
1237 <p>In the new test (test_timeout), we call <code class="python">clock.advance</code>, that simulates and advance in time
1238 (logically it's similar to a <code class="python">time.sleep</code> call). And
1239 we just have to verify that our Deferred got a timeout error.</p>
1240
1241 <p>Let's implement that in our code.</p>
1242
1243 <div class="py-listing"><pre><p class="py-linenumber"> 1
1244  2
1245  3
1246  4
1247  5
1248  6
1249  7
1250  8
1251  9
1252 10
1253 11
1254 12
1255 13
1256 14
1257 15
1258 16
1259 17
1260 18
1261 19
1262 20
1263 21
1264 22
1265 23
1266 24
1267 25
1268 26
1269 27
1270 28
1271 29
1272 30
1273 31
1274 32
1275 33
1276 34
1277 35
1278 36
1279 37
1280 38
1281 39
1282 40
1283 41
1284 42
1285 43
1286 44
1287 45
1288 46
1289 47
1290 48
1291 49
1292 50
1293 51
1294 52
1295 53
1296 54
1297 </p><span class="py-src-comment"># -*- test-case-name: calculus.test.test_client_2 -*-</span>
1298
1299 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">protocols</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">basic</span>
1300 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>, <span class="py-src-variable">reactor</span>
1301
1302
1303
1304 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ClientTimeoutError</span>(<span class="py-src-parameter">Exception</span>):
1305     <span class="py-src-keyword">pass</span>
1306
1307
1308
1309 <span class="py-src-keyword">class</span> <span class="py-src-identifier">RemoteCalculationClient</span>(<span class="py-src-parameter">basic</span>.<span class="py-src-parameter">LineReceiver</span>):
1310
1311     <span class="py-src-variable">callLater</span> = <span class="py-src-variable">reactor</span>.<span class="py-src-variable">callLater</span>
1312     <span class="py-src-variable">timeOut</span> = <span class="py-src-number">60</span>
1313
1314     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>):
1315         <span class="py-src-variable">self</span>.<span class="py-src-variable">results</span> = []
1316
1317
1318     <span class="py-src-keyword">def</span> <span class="py-src-identifier">lineReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">line</span>):
1319         <span class="py-src-variable">d</span>, <span class="py-src-variable">callID</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">results</span>.<span class="py-src-variable">pop</span>(<span class="py-src-number">0</span>)
1320         <span class="py-src-variable">callID</span>.<span class="py-src-variable">cancel</span>()
1321         <span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-variable">int</span>(<span class="py-src-variable">line</span>))
1322
1323
1324     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_cancel</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">d</span>):
1325         <span class="py-src-variable">d</span>.<span class="py-src-variable">errback</span>(<span class="py-src-variable">ClientTimeoutError</span>())
1326
1327
1328     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_sendOperation</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">op</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1329         <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
1330         <span class="py-src-variable">callID</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">callLater</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">timeOut</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">_cancel</span>, <span class="py-src-variable">d</span>)
1331         <span class="py-src-variable">self</span>.<span class="py-src-variable">results</span>.<span class="py-src-variable">append</span>((<span class="py-src-variable">d</span>, <span class="py-src-variable">callID</span>))
1332         <span class="py-src-variable">line</span> = <span class="py-src-string">&quot;%s %d %d&quot;</span> % (<span class="py-src-variable">op</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1333         <span class="py-src-variable">self</span>.<span class="py-src-variable">sendLine</span>(<span class="py-src-variable">line</span>)
1334         <span class="py-src-keyword">return</span> <span class="py-src-variable">d</span>
1335
1336
1337     <span class="py-src-keyword">def</span> <span class="py-src-identifier">add</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1338         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_sendOperation</span>(<span class="py-src-string">&quot;add&quot;</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1339
1340
1341     <span class="py-src-keyword">def</span> <span class="py-src-identifier">subtract</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1342         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_sendOperation</span>(<span class="py-src-string">&quot;subtract&quot;</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1343
1344
1345     <span class="py-src-keyword">def</span> <span class="py-src-identifier">multiply</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1346         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_sendOperation</span>(<span class="py-src-string">&quot;multiply&quot;</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1347
1348
1349     <span class="py-src-keyword">def</span> <span class="py-src-identifier">divide</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1350         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_sendOperation</span>(<span class="py-src-string">&quot;divide&quot;</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1351 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/client_2.py"><span class="filename">listings/trial/calculus/client_2.py</span></a></div></div>
1352
1353 <p>The only important thing here is to not forget to cancel our callLater
1354 when everything went fine.</p>
1355
1356 <h3>Cleaning up after tests<a name="auto10"/></h3>
1357
1358 <p>This chapter is mainly intended for people that want to have sockets or
1359 processes created in their tests. If it's still not obvious, you must try to
1360 avoid that like the plague, because it ends up with a lot of problems, one of
1361 them being intermittent failures. And intermittent failures are the plague
1362 of automated tests.</p>
1363
1364 <p>To actually test that, we'll launch a server with our protocol.</p>
1365
1366 <div class="py-listing"><pre><p class="py-linenumber"> 1
1367  2
1368  3
1369  4
1370  5
1371  6
1372  7
1373  8
1374  9
1375 10
1376 11
1377 12
1378 13
1379 14
1380 15
1381 16
1382 17
1383 18
1384 19
1385 20
1386 21
1387 22
1388 23
1389 24
1390 25
1391 26
1392 27
1393 28
1394 29
1395 30
1396 31
1397 32
1398 33
1399 34
1400 35
1401 36
1402 37
1403 38
1404 39
1405 40
1406 41
1407 42
1408 43
1409 44
1410 45
1411 46
1412 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">remote_1</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">RemoteCalculationFactory</span>
1413 <span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">client_2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">RemoteCalculationClient</span>
1414
1415 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">trial</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">unittest</span>
1416 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>, <span class="py-src-variable">protocol</span>
1417
1418
1419
1420 <span class="py-src-keyword">class</span> <span class="py-src-identifier">RemoteRunCalculationTestCase</span>(<span class="py-src-parameter">unittest</span>.<span class="py-src-parameter">TestCase</span>):
1421
1422     <span class="py-src-keyword">def</span> <span class="py-src-identifier">setUp</span>(<span class="py-src-parameter">self</span>):
1423         <span class="py-src-variable">factory</span> = <span class="py-src-variable">RemoteCalculationFactory</span>()
1424         <span class="py-src-variable">self</span>.<span class="py-src-variable">port</span> = <span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">0</span>, <span class="py-src-variable">factory</span>, <span class="py-src-variable">interface</span>=<span class="py-src-string">&quot;127.0.0.1&quot;</span>)
1425         <span class="py-src-variable">self</span>.<span class="py-src-variable">client</span> = <span class="py-src-variable">None</span>
1426
1427
1428     <span class="py-src-keyword">def</span> <span class="py-src-identifier">tearDown</span>(<span class="py-src-parameter">self</span>):
1429         <span class="py-src-keyword">if</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">client</span> <span class="py-src-keyword">is</span> <span class="py-src-keyword">not</span> <span class="py-src-variable">None</span>:
1430             <span class="py-src-variable">self</span>.<span class="py-src-variable">client</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()
1431         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">port</span>.<span class="py-src-variable">stopListening</span>()
1432
1433
1434     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_test</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">op</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>, <span class="py-src-parameter">expected</span>):
1435         <span class="py-src-variable">creator</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ClientCreator</span>(<span class="py-src-variable">reactor</span>, <span class="py-src-variable">RemoteCalculationClient</span>)
1436         <span class="py-src-keyword">def</span> <span class="py-src-identifier">cb</span>(<span class="py-src-parameter">client</span>):
1437             <span class="py-src-variable">self</span>.<span class="py-src-variable">client</span> = <span class="py-src-variable">client</span>
1438             <span class="py-src-keyword">return</span> <span class="py-src-variable">getattr</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">client</span>, <span class="py-src-variable">op</span>)(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>
1439                 ).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>, <span class="py-src-variable">expected</span>)
1440         <span class="py-src-keyword">return</span> <span class="py-src-variable">creator</span>.<span class="py-src-variable">connectTCP</span>(<span class="py-src-string">'127.0.0.1'</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">port</span>.<span class="py-src-variable">getHost</span>().<span class="py-src-variable">port</span>
1441             ).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">cb</span>)
1442
1443
1444     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_add</span>(<span class="py-src-parameter">self</span>):
1445         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">&quot;add&quot;</span>, <span class="py-src-number">5</span>, <span class="py-src-number">9</span>, <span class="py-src-number">14</span>)
1446
1447
1448     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_subtract</span>(<span class="py-src-parameter">self</span>):
1449         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">&quot;subtract&quot;</span>, <span class="py-src-number">47</span>, <span class="py-src-number">13</span>, <span class="py-src-number">34</span>)
1450
1451
1452     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_multiply</span>(<span class="py-src-parameter">self</span>):
1453         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">&quot;multiply&quot;</span>, <span class="py-src-number">7</span>, <span class="py-src-number">3</span>, <span class="py-src-number">21</span>)
1454
1455
1456     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_divide</span>(<span class="py-src-parameter">self</span>):
1457         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">&quot;divide&quot;</span>, <span class="py-src-number">84</span>, <span class="py-src-number">10</span>, <span class="py-src-number">8</span>)
1458 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/test/test_remote_2.py"><span class="filename">listings/trial/calculus/test/test_remote_2.py</span></a></div></div>
1459
1460 <p>Recent versions of trial will fail loudly if you remove the
1461  <code class="python">stopListening</code> call, which is good.</p>
1462
1463 <p>Also, you should be aware that <code class="python">tearDown</code> will
1464 called in any case, after success or failure. So don't expect that every
1465 objects you created in the test method are present, because your tests may
1466 have failed in the middle.</p>
1467
1468 <p>Trial also has a <code class="python">addCleanup</code> method, which makes
1469 these kind of cleanups easy and removes the need for <code class="python">tearDown
1470 </code>. For example, you could remove the code in <code class="python">_test</code> 
1471 this way:</p>
1472
1473 <pre class="python"><p class="py-linenumber"> 1
1474  2
1475  3
1476  4
1477  5
1478  6
1479  7
1480  8
1481  9
1482 10
1483 11
1484 </p><span class="py-src-keyword">def</span> <span class="py-src-identifier">setUp</span>(<span class="py-src-parameter">self</span>):
1485     <span class="py-src-variable">factory</span> = <span class="py-src-variable">RemoteCalculationFactory</span>()
1486     <span class="py-src-variable">self</span>.<span class="py-src-variable">port</span> = <span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">0</span>, <span class="py-src-variable">factory</span>, <span class="py-src-variable">interface</span>=<span class="py-src-string">&quot;127.0.0.1&quot;</span>)
1487     <span class="py-src-variable">self</span>.<span class="py-src-variable">addCleanup</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">port</span>.<span class="py-src-variable">stopListening</span>)
1488
1489 <span class="py-src-keyword">def</span> <span class="py-src-identifier">_test</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">op</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>, <span class="py-src-parameter">expected</span>):
1490     <span class="py-src-variable">creator</span> = <span class="py-src-variable">protocol</span>.<span class="py-src-variable">ClientCreator</span>(<span class="py-src-variable">reactor</span>, <span class="py-src-variable">RemoteCalculationClient</span>)
1491     <span class="py-src-keyword">def</span> <span class="py-src-identifier">cb</span>(<span class="py-src-parameter">client</span>):
1492         <span class="py-src-variable">self</span>.<span class="py-src-variable">addCleanup</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">client</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>)
1493         <span class="py-src-keyword">return</span> <span class="py-src-variable">getattr</span>(<span class="py-src-variable">client</span>, <span class="py-src-variable">op</span>)(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>, <span class="py-src-variable">expected</span>)
1494     <span class="py-src-keyword">return</span> <span class="py-src-variable">creator</span>.<span class="py-src-variable">connectTCP</span>(<span class="py-src-string">'127.0.0.1'</span>, <span class="py-src-variable">self</span>.<span class="py-src-variable">port</span>.<span class="py-src-variable">getHost</span>().<span class="py-src-variable">port</span>).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">cb</span>)
1495 </pre>
1496
1497 <p>This remove the need of a tearDown method, and you don't have to check for
1498 the value of self.client: you only call addCleanup when the client is
1499 created.</p>
1500
1501 <h3>Handling logged errors<a name="auto11"/></h3>
1502
1503 <p>Currently, if you send an invalid command or invalid arguments to our
1504 server, it logs an exception and closes the connection. This is a perfectly
1505 valid behavior, but for the sake of this tutorial, we want to return an error
1506 to the user if he sends invalid operators, and log any errors on server side. 
1507 So we'll want a test like this:</p>
1508
1509 <pre class="python"><p class="py-linenumber">1
1510 2
1511 3
1512 </p><span class="py-src-keyword">def</span> <span class="py-src-identifier">test_invalidParameters</span>(<span class="py-src-parameter">self</span>):
1513     <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">dataReceived</span>(<span class="py-src-string">'add foo bar\r\n'</span>)
1514     <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">value</span>(), <span class="py-src-string">&quot;error\r\n&quot;</span>)
1515 </pre>
1516
1517 <div class="py-listing"><pre><p class="py-linenumber"> 1
1518  2
1519  3
1520  4
1521  5
1522  6
1523  7
1524  8
1525  9
1526 10
1527 11
1528 12
1529 13
1530 14
1531 15
1532 16
1533 17
1534 18
1535 19
1536 20
1537 21
1538 22
1539 23
1540 24
1541 25
1542 26
1543 27
1544 28
1545 29
1546 30
1547 31
1548 32
1549 33
1550 34
1551 35
1552 36
1553 37
1554 38
1555 39
1556 40
1557 41
1558 42
1559 43
1560 44
1561 45
1562 46
1563 47
1564 48
1565 49
1566 50
1567 51
1568 </p><span class="py-src-comment"># -*- test-case-name: calculus.test.test_remote_1 -*-</span>
1569
1570 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">protocols</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">basic</span>
1571 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">protocol</span>
1572 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">log</span>
1573 <span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">base_3</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Calculation</span>
1574
1575
1576
1577 <span class="py-src-keyword">class</span> <span class="py-src-identifier">CalculationProxy</span>(<span class="py-src-parameter">object</span>):
1578     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>):
1579         <span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span> = <span class="py-src-variable">Calculation</span>()
1580         <span class="py-src-keyword">for</span> <span class="py-src-variable">m</span> <span class="py-src-keyword">in</span> [<span class="py-src-string">'add'</span>, <span class="py-src-string">'subtract'</span>, <span class="py-src-string">'multiply'</span>, <span class="py-src-string">'divide'</span>]:
1581             <span class="py-src-variable">setattr</span>(<span class="py-src-variable">self</span>, <span class="py-src-string">'remote_%s'</span> % <span class="py-src-variable">m</span>, <span class="py-src-variable">getattr</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">calc</span>, <span class="py-src-variable">m</span>))
1582
1583
1584
1585 <span class="py-src-keyword">class</span> <span class="py-src-identifier">RemoteCalculationProtocol</span>(<span class="py-src-parameter">basic</span>.<span class="py-src-parameter">LineReceiver</span>):
1586     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>):
1587         <span class="py-src-variable">self</span>.<span class="py-src-variable">proxy</span> = <span class="py-src-variable">CalculationProxy</span>()
1588
1589
1590     <span class="py-src-keyword">def</span> <span class="py-src-identifier">lineReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">line</span>):
1591         <span class="py-src-variable">op</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span> = <span class="py-src-variable">line</span>.<span class="py-src-variable">split</span>()
1592         <span class="py-src-variable">op</span> = <span class="py-src-variable">getattr</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">proxy</span>, <span class="py-src-string">'remote_%s'</span> % (<span class="py-src-variable">op</span>,))
1593         <span class="py-src-keyword">try</span>:
1594             <span class="py-src-variable">result</span> = <span class="py-src-variable">op</span>(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1595         <span class="py-src-keyword">except</span> <span class="py-src-variable">TypeError</span>:
1596             <span class="py-src-variable">log</span>.<span class="py-src-variable">err</span>()
1597             <span class="py-src-variable">self</span>.<span class="py-src-variable">sendLine</span>(<span class="py-src-string">&quot;error&quot;</span>)
1598         <span class="py-src-keyword">else</span>:
1599             <span class="py-src-variable">self</span>.<span class="py-src-variable">sendLine</span>(<span class="py-src-variable">str</span>(<span class="py-src-variable">result</span>))
1600
1601
1602
1603 <span class="py-src-keyword">class</span> <span class="py-src-identifier">RemoteCalculationFactory</span>(<span class="py-src-parameter">protocol</span>.<span class="py-src-parameter">Factory</span>):
1604     <span class="py-src-variable">protocol</span> = <span class="py-src-variable">RemoteCalculationProtocol</span>
1605
1606
1607
1608 <span class="py-src-keyword">def</span> <span class="py-src-identifier">main</span>():
1609     <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
1610     <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">log</span>
1611     <span class="py-src-keyword">import</span> <span class="py-src-variable">sys</span>
1612     <span class="py-src-variable">log</span>.<span class="py-src-variable">startLogging</span>(<span class="py-src-variable">sys</span>.<span class="py-src-variable">stdout</span>)
1613     <span class="py-src-variable">reactor</span>.<span class="py-src-variable">listenTCP</span>(<span class="py-src-number">0</span>, <span class="py-src-variable">RemoteCalculationFactory</span>())
1614     <span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
1615
1616
1617 <span class="py-src-keyword">if</span> <span class="py-src-variable">__name__</span> == <span class="py-src-string">&quot;__main__&quot;</span>:
1618     <span class="py-src-variable">main</span>()
1619 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/remote_2.py"><span class="filename">listings/trial/calculus/remote_2.py</span></a></div></div>
1620
1621 <p>If you try something like that, it will not work. Here is the output you should have:</p>
1622
1623 <pre class="shell" xml:space="preserve">
1624 trial calculus.test.test_remote_3.RemoteCalculationTestCase.test_invalidParameters
1625 calculus.test.test_remote_3
1626   RemoteCalculationTestCase
1627     test_invalidParameters ...                                          [ERROR]
1628
1629 ===============================================================================
1630 [ERROR]: calculus.test.test_remote_3.RemoteCalculationTestCase.test_invalidParameters
1631
1632 Traceback (most recent call last):
1633   File &quot;/tmp/calculus/remote_2.py&quot;, line 27, in lineReceived
1634     result = op(a, b)
1635   File &quot;/tmp/calculus/base_3.py&quot;, line 11, in add
1636     a, b = self._make_ints(a, b)
1637   File &quot;/tmp/calculus/base_3.py&quot;, line 8, in _make_ints
1638     raise TypeError
1639 exceptions.TypeError:
1640 -------------------------------------------------------------------------------
1641 Ran 1 tests in 0.004s
1642
1643 FAILED (errors=1)
1644 </pre>
1645
1646 <p>At first, you could think there is a problem, because you catch this
1647 exception. But in fact trial doesn't let you do that without controlling it:
1648 you must expect logged errors and clean them. To do that, you have to use the
1649  <code class="python">flushLoggedErrors</code> method. You call it with the
1650 exception you expect, and it returns the list of exceptions logged since the
1651 start of the test. Generally, you'll want to check that this list has the
1652 expected length, or possibly that each exception has an expected message. We do
1653 the former in our test:</p>
1654
1655 <div class="py-listing"><pre><p class="py-linenumber"> 1
1656  2
1657  3
1658  4
1659  5
1660  6
1661  7
1662  8
1663  9
1664 10
1665 11
1666 12
1667 13
1668 14
1669 15
1670 16
1671 17
1672 18
1673 19
1674 20
1675 21
1676 22
1677 23
1678 24
1679 25
1680 26
1681 27
1682 28
1683 29
1684 30
1685 31
1686 32
1687 33
1688 34
1689 35
1690 36
1691 37
1692 38
1693 39
1694 40
1695 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">remote_2</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">RemoteCalculationFactory</span>
1696 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">trial</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">unittest</span>
1697 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">test</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">proto_helpers</span>
1698
1699
1700
1701 <span class="py-src-keyword">class</span> <span class="py-src-identifier">RemoteCalculationTestCase</span>(<span class="py-src-parameter">unittest</span>.<span class="py-src-parameter">TestCase</span>):
1702     <span class="py-src-keyword">def</span> <span class="py-src-identifier">setUp</span>(<span class="py-src-parameter">self</span>):
1703         <span class="py-src-variable">factory</span> = <span class="py-src-variable">RemoteCalculationFactory</span>()
1704         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span> = <span class="py-src-variable">factory</span>.<span class="py-src-variable">buildProtocol</span>((<span class="py-src-string">'127.0.0.1'</span>, <span class="py-src-number">0</span>))
1705         <span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span> = <span class="py-src-variable">proto_helpers</span>.<span class="py-src-variable">StringTransport</span>()
1706         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">makeConnection</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>)
1707
1708
1709     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_test</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">operation</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>, <span class="py-src-parameter">expected</span>):
1710         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">dataReceived</span>(<span class="py-src-string">'%s %d %d\r\n'</span> % (<span class="py-src-variable">operation</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>))
1711         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">int</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">value</span>()), <span class="py-src-variable">expected</span>)
1712
1713
1714     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_add</span>(<span class="py-src-parameter">self</span>):
1715         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'add'</span>, <span class="py-src-number">7</span>, <span class="py-src-number">6</span>, <span class="py-src-number">13</span>)
1716
1717
1718     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_subtract</span>(<span class="py-src-parameter">self</span>):
1719         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'subtract'</span>, <span class="py-src-number">82</span>, <span class="py-src-number">78</span>, <span class="py-src-number">4</span>)
1720
1721
1722     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_multiply</span>(<span class="py-src-parameter">self</span>):
1723         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'multiply'</span>, <span class="py-src-number">2</span>, <span class="py-src-number">8</span>, <span class="py-src-number">16</span>)
1724
1725
1726     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_divide</span>(<span class="py-src-parameter">self</span>):
1727         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'divide'</span>, <span class="py-src-number">14</span>, <span class="py-src-number">3</span>, <span class="py-src-number">4</span>)
1728
1729
1730     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_invalidParameters</span>(<span class="py-src-parameter">self</span>):
1731         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">dataReceived</span>(<span class="py-src-string">'add foo bar\r\n'</span>)
1732         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">value</span>(), <span class="py-src-string">&quot;error\r\n&quot;</span>)
1733         <span class="py-src-variable">errors</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">flushLoggedErrors</span>(<span class="py-src-variable">TypeError</span>)
1734         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">len</span>(<span class="py-src-variable">errors</span>), <span class="py-src-number">1</span>)
1735 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/test/test_remote_3.py"><span class="filename">listings/trial/calculus/test/test_remote_3.py</span></a></div></div>
1736
1737 <h2>Resolve a bug<a name="auto12"/></h2>
1738
1739 <p>A bug was left over during the development of the timeout (probably several
1740 bugs, but that's not the point), concerning the reuse of the protocol when you
1741 got a timeout: the connection is not dropped, so you can get timeout forever.
1742 Generally an user will come to you saying &quot;I have this strange problem on
1743 my crappy network environment. It seems you could solve it with doing XXX at
1744 YYY.&quot;</p>
1745
1746 <p>Actually, this bug can be corrected several ways. But if you correct it 
1747 without adding tests, one day you'll face a big problem: regression. 
1748 So the first step is adding a failing test.</p>
1749
1750 <div class="py-listing"><pre><p class="py-linenumber"> 1
1751  2
1752  3
1753  4
1754  5
1755  6
1756  7
1757  8
1758  9
1759 10
1760 11
1761 12
1762 13
1763 14
1764 15
1765 16
1766 17
1767 18
1768 19
1769 20
1770 21
1771 22
1772 23
1773 24
1774 25
1775 26
1776 27
1777 28
1778 29
1779 30
1780 31
1781 32
1782 33
1783 34
1784 35
1785 36
1786 37
1787 38
1788 39
1789 40
1790 41
1791 42
1792 43
1793 44
1794 45
1795 46
1796 47
1797 48
1798 49
1799 50
1800 51
1801 52
1802 53
1803 54
1804 55
1805 56
1806 57
1807 58
1808 59
1809 60
1810 61
1811 62
1812 63
1813 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">calculus</span>.<span class="py-src-variable">client_3</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">RemoteCalculationClient</span>, <span class="py-src-variable">ClientTimeoutError</span>
1814
1815 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">task</span>
1816 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">trial</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">unittest</span>
1817 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">test</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">proto_helpers</span>
1818
1819
1820
1821 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ClientCalculationTestCase</span>(<span class="py-src-parameter">unittest</span>.<span class="py-src-parameter">TestCase</span>):
1822     <span class="py-src-keyword">def</span> <span class="py-src-identifier">setUp</span>(<span class="py-src-parameter">self</span>):
1823         <span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span> = <span class="py-src-variable">proto_helpers</span>.<span class="py-src-variable">StringTransportWithDisconnection</span>()
1824         <span class="py-src-variable">self</span>.<span class="py-src-variable">clock</span> = <span class="py-src-variable">task</span>.<span class="py-src-variable">Clock</span>()
1825         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span> = <span class="py-src-variable">RemoteCalculationClient</span>()
1826         <span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">protocol</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>
1827         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">callLater</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">clock</span>.<span class="py-src-variable">callLater</span>
1828         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">makeConnection</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>)
1829
1830
1831     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_test</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">operation</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>, <span class="py-src-parameter">expected</span>):
1832         <span class="py-src-variable">d</span> = <span class="py-src-variable">getattr</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>, <span class="py-src-variable">operation</span>)(<span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1833         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">value</span>(), <span class="py-src-string">'%s %d %d\r\n'</span> % (<span class="py-src-variable">operation</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>))
1834         <span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">clear</span>()
1835         <span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>, <span class="py-src-variable">expected</span>)
1836         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">dataReceived</span>(<span class="py-src-string">&quot;%d\r\n&quot;</span> % (<span class="py-src-variable">expected</span>,))
1837         <span class="py-src-keyword">return</span> <span class="py-src-variable">d</span>
1838
1839
1840     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_add</span>(<span class="py-src-parameter">self</span>):
1841         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'add'</span>, <span class="py-src-number">7</span>, <span class="py-src-number">6</span>, <span class="py-src-number">13</span>)
1842
1843
1844     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_subtract</span>(<span class="py-src-parameter">self</span>):
1845         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'subtract'</span>, <span class="py-src-number">82</span>, <span class="py-src-number">78</span>, <span class="py-src-number">4</span>)
1846
1847
1848     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_multiply</span>(<span class="py-src-parameter">self</span>):
1849         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'multiply'</span>, <span class="py-src-number">2</span>, <span class="py-src-number">8</span>, <span class="py-src-number">16</span>)
1850
1851
1852     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_divide</span>(<span class="py-src-parameter">self</span>):
1853         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_test</span>(<span class="py-src-string">'divide'</span>, <span class="py-src-number">14</span>, <span class="py-src-number">3</span>, <span class="py-src-number">4</span>)
1854
1855
1856     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_timeout</span>(<span class="py-src-parameter">self</span>):
1857         <span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">add</span>(<span class="py-src-number">9</span>, <span class="py-src-number">4</span>)
1858         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">value</span>(), <span class="py-src-string">'add 9 4\r\n'</span>)
1859         <span class="py-src-variable">self</span>.<span class="py-src-variable">clock</span>.<span class="py-src-variable">advance</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">timeOut</span>)
1860         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">assertFailure</span>(<span class="py-src-variable">d</span>, <span class="py-src-variable">ClientTimeoutError</span>)
1861
1862
1863     <span class="py-src-keyword">def</span> <span class="py-src-identifier">test_timeoutConnectionLost</span>(<span class="py-src-parameter">self</span>):
1864         <span class="py-src-variable">called</span> = []
1865         <span class="py-src-keyword">def</span> <span class="py-src-identifier">lost</span>(<span class="py-src-parameter">arg</span>):
1866             <span class="py-src-variable">called</span>.<span class="py-src-variable">append</span>(<span class="py-src-variable">True</span>)
1867         <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">connectionLost</span> = <span class="py-src-variable">lost</span>
1868
1869         <span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">add</span>(<span class="py-src-number">9</span>, <span class="py-src-number">4</span>)
1870         <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">tr</span>.<span class="py-src-variable">value</span>(), <span class="py-src-string">'add 9 4\r\n'</span>)
1871         <span class="py-src-variable">self</span>.<span class="py-src-variable">clock</span>.<span class="py-src-variable">advance</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">proto</span>.<span class="py-src-variable">timeOut</span>)
1872
1873         <span class="py-src-keyword">def</span> <span class="py-src-identifier">check</span>(<span class="py-src-parameter">ignore</span>):
1874             <span class="py-src-variable">self</span>.<span class="py-src-variable">assertEqual</span>(<span class="py-src-variable">called</span>, [<span class="py-src-variable">True</span>])
1875         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">assertFailure</span>(<span class="py-src-variable">d</span>, <span class="py-src-variable">ClientTimeoutError</span>).<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">check</span>)
1876 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/test/test_client_3.py"><span class="filename">listings/trial/calculus/test/test_client_3.py</span></a></div></div>
1877 <p>What have we done here ?
1878 <ul>
1879     <li>We switched to StringTransportWithDisconnection. This transport manages
1880     <code class="python">loseConnection</code> and forwards it to its protocol.</li>
1881     <li>We assign the protocol to the transport via the <code class="python">protocol 
1882    </code> attribute.</li>
1883     <li>We check that after a timeout our connection has closed.</li>
1884 </ul>
1885 </p>
1886
1887 <p>For doing that, we then use the <code class="python">TimeoutMixin</code>
1888 class, that does almost everything we want. The great thing is that it almost
1889 changes nothing to our class.</p>
1890
1891 <div class="py-listing"><pre><p class="py-linenumber"> 1
1892  2
1893  3
1894  4
1895  5
1896  6
1897  7
1898  8
1899  9
1900 10
1901 11
1902 12
1903 13
1904 14
1905 15
1906 16
1907 17
1908 18
1909 19
1910 20
1911 21
1912 22
1913 23
1914 24
1915 25
1916 26
1917 27
1918 28
1919 29
1920 30
1921 31
1922 32
1923 33
1924 34
1925 35
1926 36
1927 37
1928 38
1929 39
1930 40
1931 41
1932 42
1933 43
1934 44
1935 45
1936 46
1937 47
1938 48
1939 49
1940 50
1941 51
1942 52
1943 53
1944 </p><span class="py-src-comment"># -*- test-case-name: calculus.test.test_client -*-</span>
1945
1946 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">protocols</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">basic</span>, <span class="py-src-variable">policies</span>
1947 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">defer</span>
1948
1949
1950
1951 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ClientTimeoutError</span>(<span class="py-src-parameter">Exception</span>):
1952     <span class="py-src-keyword">pass</span>
1953
1954
1955
1956 <span class="py-src-keyword">class</span> <span class="py-src-identifier">RemoteCalculationClient</span>(<span class="py-src-parameter">object</span>, <span class="py-src-parameter">basic</span>.<span class="py-src-parameter">LineReceiver</span>, <span class="py-src-parameter">policies</span>.<span class="py-src-parameter">TimeoutMixin</span>):
1957
1958     <span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>):
1959         <span class="py-src-variable">self</span>.<span class="py-src-variable">results</span> = []
1960         <span class="py-src-variable">self</span>.<span class="py-src-variable">_timeOut</span> = <span class="py-src-number">60</span>
1961
1962     <span class="py-src-keyword">def</span> <span class="py-src-identifier">lineReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">line</span>):
1963         <span class="py-src-variable">self</span>.<span class="py-src-variable">setTimeout</span>(<span class="py-src-variable">None</span>)
1964         <span class="py-src-variable">d</span> = <span class="py-src-variable">self</span>.<span class="py-src-variable">results</span>.<span class="py-src-variable">pop</span>(<span class="py-src-number">0</span>)
1965         <span class="py-src-variable">d</span>.<span class="py-src-variable">callback</span>(<span class="py-src-variable">int</span>(<span class="py-src-variable">line</span>))
1966
1967
1968     <span class="py-src-keyword">def</span> <span class="py-src-identifier">timeoutConnection</span>(<span class="py-src-parameter">self</span>):
1969         <span class="py-src-keyword">for</span> <span class="py-src-variable">d</span> <span class="py-src-keyword">in</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">results</span>:
1970             <span class="py-src-variable">d</span>.<span class="py-src-variable">errback</span>(<span class="py-src-variable">ClientTimeoutError</span>())
1971         <span class="py-src-variable">self</span>.<span class="py-src-variable">transport</span>.<span class="py-src-variable">loseConnection</span>()
1972
1973
1974     <span class="py-src-keyword">def</span> <span class="py-src-identifier">_sendOperation</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">op</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1975         <span class="py-src-variable">d</span> = <span class="py-src-variable">defer</span>.<span class="py-src-variable">Deferred</span>()
1976         <span class="py-src-variable">self</span>.<span class="py-src-variable">results</span>.<span class="py-src-variable">append</span>(<span class="py-src-variable">d</span>)
1977         <span class="py-src-variable">line</span> = <span class="py-src-string">&quot;%s %d %d&quot;</span> % (<span class="py-src-variable">op</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1978         <span class="py-src-variable">self</span>.<span class="py-src-variable">sendLine</span>(<span class="py-src-variable">line</span>)
1979         <span class="py-src-variable">self</span>.<span class="py-src-variable">setTimeout</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">_timeOut</span>)
1980         <span class="py-src-keyword">return</span> <span class="py-src-variable">d</span>
1981
1982
1983     <span class="py-src-keyword">def</span> <span class="py-src-identifier">add</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1984         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_sendOperation</span>(<span class="py-src-string">&quot;add&quot;</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1985
1986
1987     <span class="py-src-keyword">def</span> <span class="py-src-identifier">subtract</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1988         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_sendOperation</span>(<span class="py-src-string">&quot;subtract&quot;</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1989
1990
1991     <span class="py-src-keyword">def</span> <span class="py-src-identifier">multiply</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1992         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_sendOperation</span>(<span class="py-src-string">&quot;multiply&quot;</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1993
1994
1995     <span class="py-src-keyword">def</span> <span class="py-src-identifier">divide</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">a</span>, <span class="py-src-parameter">b</span>):
1996         <span class="py-src-keyword">return</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">_sendOperation</span>(<span class="py-src-string">&quot;divide&quot;</span>, <span class="py-src-variable">a</span>, <span class="py-src-variable">b</span>)
1997 </pre><div class="caption">Source listing - <a href="listings/trial/calculus/client_3.py"><span class="filename">listings/trial/calculus/client_3.py</span></a></div></div>
1998
1999 <h2>Code coverage<a name="auto13"/></h2>
2000
2001 <p>Code coverage is one of the aspects of software testing that shows how much
2002 your tests cross (cover) the code of your program. There are different kind of
2003 measures: path coverage, condition coverage, statement coverage... We'll only
2004 consider statement coverage here, whether a line has been executed or not.
2005 </p>
2006
2007 <p>Trial has an option to generate the statement coverage of your tests.
2008 This option is --coverage. It creates a coverage directory in _trial_temp,
2009 with a file .cover for every modules used during the tests. The ones
2010 interesting for us are calculus.base.cover and calculus.remote.cover.  In
2011 front of each line is the number of times you went through during the
2012 tests, or the marker '&gt;&gt;&gt;&gt;&gt;&gt;' if the line was not
2013 covered. If you went through all the tutorial to this point, you should
2014 have complete coverage :).</p>
2015
2016 <p>Again, this is only another useful pointer, but it doesn't mean your
2017 code is perfect: your tests should consider every possibile input and
2018 output, to get <strong>full</strong> coverage (condition, path, etc.) as well
2019 .</p>
2020
2021 <h2>Conclusion<a name="auto14"/></h2>
2022
2023 <p>So what did you learn in this document?
2024 <ul>
2025     <li>How to use the trial command-line tool to run your tests</li>
2026     <li>How to use string transports to test individual clients and servers
2027     without creating sockets</li>
2028     <li>If you really want to create sockets, how to cleanly do it so that it
2029     doesn't have bad side effects</li>
2030     <li>And some small tips you can't live without.</li>
2031 </ul>
2032 If one of the topics still looks cloudy to you, please give us your feedback!
2033 You can file tickets to improve this document
2034 <a href="http://twistedmatrix.com/" shape="rect">on the Twisted web site</a>.
2035 </p>
2036
2037 </div>
2038
2039     <p><a href="index.html">Index</a></p>
2040     <span class="version">Version: 12.1.0</span>
2041   </body>
2042 </html>