blob: 489fe177546add9f790bcc1c5a94a4463292b61b [file] [log] [blame]
Michael Foord2560e5c2010-03-27 12:34:21 +00001import io
2import sys
Benjamin Petersonb48af542010-04-11 20:43:16 +00003import textwrap
Michael Foord2560e5c2010-03-27 12:34:21 +00004
5from test import support
6
Michael Foordd23ea062010-05-02 21:00:22 +00007import traceback
Michael Foord2560e5c2010-03-27 12:34:21 +00008import unittest
9
10
11class Test_TestResult(unittest.TestCase):
12 # Note: there are not separate tests for TestResult.wasSuccessful(),
13 # TestResult.errors, TestResult.failures, TestResult.testsRun or
14 # TestResult.shouldStop because these only have meaning in terms of
15 # other TestResult methods.
16 #
17 # Accordingly, tests for the aforenamed attributes are incorporated
18 # in with the tests for the defining methods.
19 ################################################################
20
21 def test_init(self):
22 result = unittest.TestResult()
23
24 self.assertTrue(result.wasSuccessful())
25 self.assertEqual(len(result.errors), 0)
26 self.assertEqual(len(result.failures), 0)
27 self.assertEqual(result.testsRun, 0)
28 self.assertEqual(result.shouldStop, False)
Benjamin Petersonb48af542010-04-11 20:43:16 +000029 self.assertIsNone(result._stdout_buffer)
30 self.assertIsNone(result._stderr_buffer)
Michael Foord2560e5c2010-03-27 12:34:21 +000031
32 # "This method can be called to signal that the set of tests being
33 # run should be aborted by setting the TestResult's shouldStop
34 # attribute to True."
35 def test_stop(self):
36 result = unittest.TestResult()
37
38 result.stop()
39
40 self.assertEqual(result.shouldStop, True)
41
42 # "Called when the test case test is about to be run. The default
43 # implementation simply increments the instance's testsRun counter."
44 def test_startTest(self):
45 class Foo(unittest.TestCase):
46 def test_1(self):
47 pass
48
49 test = Foo('test_1')
50
51 result = unittest.TestResult()
52
53 result.startTest(test)
54
55 self.assertTrue(result.wasSuccessful())
56 self.assertEqual(len(result.errors), 0)
57 self.assertEqual(len(result.failures), 0)
58 self.assertEqual(result.testsRun, 1)
59 self.assertEqual(result.shouldStop, False)
60
61 result.stopTest(test)
62
63 # "Called after the test case test has been executed, regardless of
64 # the outcome. The default implementation does nothing."
65 def test_stopTest(self):
66 class Foo(unittest.TestCase):
67 def test_1(self):
68 pass
69
70 test = Foo('test_1')
71
72 result = unittest.TestResult()
73
74 result.startTest(test)
75
76 self.assertTrue(result.wasSuccessful())
77 self.assertEqual(len(result.errors), 0)
78 self.assertEqual(len(result.failures), 0)
79 self.assertEqual(result.testsRun, 1)
80 self.assertEqual(result.shouldStop, False)
81
82 result.stopTest(test)
83
84 # Same tests as above; make sure nothing has changed
85 self.assertTrue(result.wasSuccessful())
86 self.assertEqual(len(result.errors), 0)
87 self.assertEqual(len(result.failures), 0)
88 self.assertEqual(result.testsRun, 1)
89 self.assertEqual(result.shouldStop, False)
90
91 # "Called before and after tests are run. The default implementation does nothing."
92 def test_startTestRun_stopTestRun(self):
93 result = unittest.TestResult()
94 result.startTestRun()
95 result.stopTestRun()
96
97 # "addSuccess(test)"
98 # ...
99 # "Called when the test case test succeeds"
100 # ...
101 # "wasSuccessful() - Returns True if all tests run so far have passed,
102 # otherwise returns False"
103 # ...
104 # "testsRun - The total number of tests run so far."
105 # ...
106 # "errors - A list containing 2-tuples of TestCase instances and
107 # formatted tracebacks. Each tuple represents a test which raised an
108 # unexpected exception. Contains formatted
109 # tracebacks instead of sys.exc_info() results."
110 # ...
111 # "failures - A list containing 2-tuples of TestCase instances and
112 # formatted tracebacks. Each tuple represents a test where a failure was
113 # explicitly signalled using the TestCase.fail*() or TestCase.assert*()
114 # methods. Contains formatted tracebacks instead
115 # of sys.exc_info() results."
116 def test_addSuccess(self):
117 class Foo(unittest.TestCase):
118 def test_1(self):
119 pass
120
121 test = Foo('test_1')
122
123 result = unittest.TestResult()
124
125 result.startTest(test)
126 result.addSuccess(test)
127 result.stopTest(test)
128
129 self.assertTrue(result.wasSuccessful())
130 self.assertEqual(len(result.errors), 0)
131 self.assertEqual(len(result.failures), 0)
132 self.assertEqual(result.testsRun, 1)
133 self.assertEqual(result.shouldStop, False)
134
135 # "addFailure(test, err)"
136 # ...
137 # "Called when the test case test signals a failure. err is a tuple of
138 # the form returned by sys.exc_info(): (type, value, traceback)"
139 # ...
140 # "wasSuccessful() - Returns True if all tests run so far have passed,
141 # otherwise returns False"
142 # ...
143 # "testsRun - The total number of tests run so far."
144 # ...
145 # "errors - A list containing 2-tuples of TestCase instances and
146 # formatted tracebacks. Each tuple represents a test which raised an
147 # unexpected exception. Contains formatted
148 # tracebacks instead of sys.exc_info() results."
149 # ...
150 # "failures - A list containing 2-tuples of TestCase instances and
151 # formatted tracebacks. Each tuple represents a test where a failure was
152 # explicitly signalled using the TestCase.fail*() or TestCase.assert*()
153 # methods. Contains formatted tracebacks instead
154 # of sys.exc_info() results."
155 def test_addFailure(self):
156 class Foo(unittest.TestCase):
157 def test_1(self):
158 pass
159
160 test = Foo('test_1')
161 try:
162 test.fail("foo")
163 except:
164 exc_info_tuple = sys.exc_info()
165
166 result = unittest.TestResult()
167
168 result.startTest(test)
169 result.addFailure(test, exc_info_tuple)
170 result.stopTest(test)
171
172 self.assertFalse(result.wasSuccessful())
173 self.assertEqual(len(result.errors), 0)
174 self.assertEqual(len(result.failures), 1)
175 self.assertEqual(result.testsRun, 1)
176 self.assertEqual(result.shouldStop, False)
177
178 test_case, formatted_exc = result.failures[0]
Serhiy Storchaka5665bc52013-11-17 00:12:21 +0200179 self.assertIs(test_case, test)
Michael Foord2560e5c2010-03-27 12:34:21 +0000180 self.assertIsInstance(formatted_exc, str)
181
182 # "addError(test, err)"
183 # ...
184 # "Called when the test case test raises an unexpected exception err
185 # is a tuple of the form returned by sys.exc_info():
186 # (type, value, traceback)"
187 # ...
188 # "wasSuccessful() - Returns True if all tests run so far have passed,
189 # otherwise returns False"
190 # ...
191 # "testsRun - The total number of tests run so far."
192 # ...
193 # "errors - A list containing 2-tuples of TestCase instances and
194 # formatted tracebacks. Each tuple represents a test which raised an
195 # unexpected exception. Contains formatted
196 # tracebacks instead of sys.exc_info() results."
197 # ...
198 # "failures - A list containing 2-tuples of TestCase instances and
199 # formatted tracebacks. Each tuple represents a test where a failure was
200 # explicitly signalled using the TestCase.fail*() or TestCase.assert*()
201 # methods. Contains formatted tracebacks instead
202 # of sys.exc_info() results."
203 def test_addError(self):
204 class Foo(unittest.TestCase):
205 def test_1(self):
206 pass
207
208 test = Foo('test_1')
209 try:
210 raise TypeError()
211 except:
212 exc_info_tuple = sys.exc_info()
213
214 result = unittest.TestResult()
215
216 result.startTest(test)
217 result.addError(test, exc_info_tuple)
218 result.stopTest(test)
219
220 self.assertFalse(result.wasSuccessful())
221 self.assertEqual(len(result.errors), 1)
222 self.assertEqual(len(result.failures), 0)
223 self.assertEqual(result.testsRun, 1)
224 self.assertEqual(result.shouldStop, False)
225
226 test_case, formatted_exc = result.errors[0]
Serhiy Storchaka5665bc52013-11-17 00:12:21 +0200227 self.assertIs(test_case, test)
Michael Foord2560e5c2010-03-27 12:34:21 +0000228 self.assertIsInstance(formatted_exc, str)
229
Antoine Pitrou22e162f2013-03-29 17:55:24 +0100230 def test_addSubTest(self):
231 class Foo(unittest.TestCase):
232 def test_1(self):
233 nonlocal subtest
234 with self.subTest(foo=1):
235 subtest = self._subtest
236 try:
237 1/0
238 except ZeroDivisionError:
239 exc_info_tuple = sys.exc_info()
240 # Register an error by hand (to check the API)
241 result.addSubTest(test, subtest, exc_info_tuple)
242 # Now trigger a failure
243 self.fail("some recognizable failure")
244
245 subtest = None
246 test = Foo('test_1')
247 result = unittest.TestResult()
248
249 test.run(result)
250
251 self.assertFalse(result.wasSuccessful())
252 self.assertEqual(len(result.errors), 1)
253 self.assertEqual(len(result.failures), 1)
254 self.assertEqual(result.testsRun, 1)
255 self.assertEqual(result.shouldStop, False)
256
257 test_case, formatted_exc = result.errors[0]
258 self.assertIs(test_case, subtest)
259 self.assertIn("ZeroDivisionError", formatted_exc)
260 test_case, formatted_exc = result.failures[0]
261 self.assertIs(test_case, subtest)
262 self.assertIn("some recognizable failure", formatted_exc)
263
Michael Foord2560e5c2010-03-27 12:34:21 +0000264 def testGetDescriptionWithoutDocstring(self):
265 result = unittest.TextTestResult(None, True, 1)
266 self.assertEqual(
267 result.getDescription(self),
268 'testGetDescriptionWithoutDocstring (' + __name__ +
269 '.Test_TestResult)')
270
Antoine Pitrouc9b3ef22013-03-20 20:16:47 +0100271 def testGetSubTestDescriptionWithoutDocstring(self):
272 with self.subTest(foo=1, bar=2):
273 result = unittest.TextTestResult(None, True, 1)
274 self.assertEqual(
275 result.getDescription(self._subtest),
276 'testGetSubTestDescriptionWithoutDocstring (' + __name__ +
277 '.Test_TestResult) (bar=2, foo=1)')
278 with self.subTest('some message'):
279 result = unittest.TextTestResult(None, True, 1)
280 self.assertEqual(
281 result.getDescription(self._subtest),
282 'testGetSubTestDescriptionWithoutDocstring (' + __name__ +
283 '.Test_TestResult) [some message]')
284
285 def testGetSubTestDescriptionWithoutDocstringAndParams(self):
286 with self.subTest():
287 result = unittest.TextTestResult(None, True, 1)
288 self.assertEqual(
289 result.getDescription(self._subtest),
290 'testGetSubTestDescriptionWithoutDocstringAndParams '
291 '(' + __name__ + '.Test_TestResult) (<subtest>)')
292
293 def testGetNestedSubTestDescriptionWithoutDocstring(self):
294 with self.subTest(foo=1):
295 with self.subTest(bar=2):
296 result = unittest.TextTestResult(None, True, 1)
297 self.assertEqual(
298 result.getDescription(self._subtest),
299 'testGetNestedSubTestDescriptionWithoutDocstring '
300 '(' + __name__ + '.Test_TestResult) (bar=2, foo=1)')
301
Michael Foord2560e5c2010-03-27 12:34:21 +0000302 @unittest.skipIf(sys.flags.optimize >= 2,
303 "Docstrings are omitted with -O2 and above")
304 def testGetDescriptionWithOneLineDocstring(self):
305 """Tests getDescription() for a method with a docstring."""
306 result = unittest.TextTestResult(None, True, 1)
307 self.assertEqual(
308 result.getDescription(self),
309 ('testGetDescriptionWithOneLineDocstring '
310 '(' + __name__ + '.Test_TestResult)\n'
311 'Tests getDescription() for a method with a docstring.'))
312
313 @unittest.skipIf(sys.flags.optimize >= 2,
314 "Docstrings are omitted with -O2 and above")
Antoine Pitrouc9b3ef22013-03-20 20:16:47 +0100315 def testGetSubTestDescriptionWithOneLineDocstring(self):
316 """Tests getDescription() for a method with a docstring."""
317 result = unittest.TextTestResult(None, True, 1)
318 with self.subTest(foo=1, bar=2):
319 self.assertEqual(
320 result.getDescription(self._subtest),
321 ('testGetSubTestDescriptionWithOneLineDocstring '
322 '(' + __name__ + '.Test_TestResult) (bar=2, foo=1)\n'
323 'Tests getDescription() for a method with a docstring.'))
324
325 @unittest.skipIf(sys.flags.optimize >= 2,
326 "Docstrings are omitted with -O2 and above")
Michael Foord2560e5c2010-03-27 12:34:21 +0000327 def testGetDescriptionWithMultiLineDocstring(self):
328 """Tests getDescription() for a method with a longer docstring.
329 The second line of the docstring.
330 """
331 result = unittest.TextTestResult(None, True, 1)
332 self.assertEqual(
333 result.getDescription(self),
334 ('testGetDescriptionWithMultiLineDocstring '
335 '(' + __name__ + '.Test_TestResult)\n'
336 'Tests getDescription() for a method with a longer '
337 'docstring.'))
338
Antoine Pitrouc9b3ef22013-03-20 20:16:47 +0100339 @unittest.skipIf(sys.flags.optimize >= 2,
340 "Docstrings are omitted with -O2 and above")
341 def testGetSubTestDescriptionWithMultiLineDocstring(self):
342 """Tests getDescription() for a method with a longer docstring.
343 The second line of the docstring.
344 """
345 result = unittest.TextTestResult(None, True, 1)
346 with self.subTest(foo=1, bar=2):
347 self.assertEqual(
348 result.getDescription(self._subtest),
349 ('testGetSubTestDescriptionWithMultiLineDocstring '
350 '(' + __name__ + '.Test_TestResult) (bar=2, foo=1)\n'
351 'Tests getDescription() for a method with a longer '
352 'docstring.'))
353
Michael Foord2560e5c2010-03-27 12:34:21 +0000354 def testStackFrameTrimming(self):
355 class Frame(object):
356 class tb_frame(object):
357 f_globals = {}
358 result = unittest.TestResult()
359 self.assertFalse(result._is_relevant_tb_level(Frame))
360
361 Frame.tb_frame.f_globals['__unittest'] = True
362 self.assertTrue(result._is_relevant_tb_level(Frame))
363
364 def testFailFast(self):
365 result = unittest.TestResult()
366 result._exc_info_to_string = lambda *_: ''
367 result.failfast = True
368 result.addError(None, None)
369 self.assertTrue(result.shouldStop)
370
371 result = unittest.TestResult()
372 result._exc_info_to_string = lambda *_: ''
373 result.failfast = True
374 result.addFailure(None, None)
375 self.assertTrue(result.shouldStop)
376
377 result = unittest.TestResult()
378 result._exc_info_to_string = lambda *_: ''
379 result.failfast = True
380 result.addUnexpectedSuccess(None)
381 self.assertTrue(result.shouldStop)
382
383 def testFailFastSetByRunner(self):
384 runner = unittest.TextTestRunner(stream=io.StringIO(), failfast=True)
385 def test(result):
386 self.assertTrue(result.failfast)
387 result = runner.run(test)
388
389
390classDict = dict(unittest.TestResult.__dict__)
391for m in ('addSkip', 'addExpectedFailure', 'addUnexpectedSuccess',
392 '__init__'):
393 del classDict[m]
394
395def __init__(self, stream=None, descriptions=None, verbosity=None):
396 self.failures = []
397 self.errors = []
398 self.testsRun = 0
399 self.shouldStop = False
Benjamin Petersonb48af542010-04-11 20:43:16 +0000400 self.buffer = False
401
Michael Foord2560e5c2010-03-27 12:34:21 +0000402classDict['__init__'] = __init__
403OldResult = type('OldResult', (object,), classDict)
404
405class Test_OldTestResult(unittest.TestCase):
406
407 def assertOldResultWarning(self, test, failures):
Florent Xiclunafd1b0932010-03-28 00:25:02 +0000408 with support.check_warnings(("TestResult has no add.+ method,",
409 RuntimeWarning)):
Michael Foord2560e5c2010-03-27 12:34:21 +0000410 result = OldResult()
411 test.run(result)
412 self.assertEqual(len(result.failures), failures)
Michael Foord2560e5c2010-03-27 12:34:21 +0000413
414 def testOldTestResult(self):
415 class Test(unittest.TestCase):
416 def testSkip(self):
417 self.skipTest('foobar')
418 @unittest.expectedFailure
419 def testExpectedFail(self):
420 raise TypeError
421 @unittest.expectedFailure
422 def testUnexpectedSuccess(self):
423 pass
424
425 for test_name, should_pass in (('testSkip', True),
426 ('testExpectedFail', True),
427 ('testUnexpectedSuccess', False)):
428 test = Test(test_name)
429 self.assertOldResultWarning(test, int(not should_pass))
430
431 def testOldTestTesultSetup(self):
432 class Test(unittest.TestCase):
433 def setUp(self):
434 self.skipTest('no reason')
435 def testFoo(self):
436 pass
437 self.assertOldResultWarning(Test('testFoo'), 0)
438
439 def testOldTestResultClass(self):
440 @unittest.skip('no reason')
441 class Test(unittest.TestCase):
442 def testFoo(self):
443 pass
444 self.assertOldResultWarning(Test('testFoo'), 0)
445
446 def testOldResultWithRunner(self):
447 class Test(unittest.TestCase):
448 def testFoo(self):
449 pass
450 runner = unittest.TextTestRunner(resultclass=OldResult,
451 stream=io.StringIO())
452 # This will raise an exception if TextTestRunner can't handle old
453 # test result objects
454 runner.run(Test('testFoo'))
Benjamin Petersonb48af542010-04-11 20:43:16 +0000455
456
Michael Foordd23ea062010-05-02 21:00:22 +0000457class MockTraceback(object):
458 @staticmethod
459 def format_exception(*_):
460 return ['A traceback']
461
462def restore_traceback():
463 unittest.result.traceback = traceback
464
465
Benjamin Petersonb48af542010-04-11 20:43:16 +0000466class TestOutputBuffering(unittest.TestCase):
467
468 def setUp(self):
469 self._real_out = sys.stdout
470 self._real_err = sys.stderr
471
472 def tearDown(self):
473 sys.stdout = self._real_out
474 sys.stderr = self._real_err
475
476 def testBufferOutputOff(self):
477 real_out = self._real_out
478 real_err = self._real_err
479
480 result = unittest.TestResult()
481 self.assertFalse(result.buffer)
482
483 self.assertIs(real_out, sys.stdout)
484 self.assertIs(real_err, sys.stderr)
485
486 result.startTest(self)
487
488 self.assertIs(real_out, sys.stdout)
489 self.assertIs(real_err, sys.stderr)
490
491 def testBufferOutputStartTestAddSuccess(self):
492 real_out = self._real_out
493 real_err = self._real_err
494
495 result = unittest.TestResult()
496 self.assertFalse(result.buffer)
497
498 result.buffer = True
499
500 self.assertIs(real_out, sys.stdout)
501 self.assertIs(real_err, sys.stderr)
502
503 result.startTest(self)
504
505 self.assertIsNot(real_out, sys.stdout)
506 self.assertIsNot(real_err, sys.stderr)
507 self.assertIsInstance(sys.stdout, io.StringIO)
508 self.assertIsInstance(sys.stderr, io.StringIO)
509 self.assertIsNot(sys.stdout, sys.stderr)
510
511 out_stream = sys.stdout
512 err_stream = sys.stderr
513
514 result._original_stdout = io.StringIO()
515 result._original_stderr = io.StringIO()
516
517 print('foo')
518 print('bar', file=sys.stderr)
519
520 self.assertEqual(out_stream.getvalue(), 'foo\n')
521 self.assertEqual(err_stream.getvalue(), 'bar\n')
522
523 self.assertEqual(result._original_stdout.getvalue(), '')
524 self.assertEqual(result._original_stderr.getvalue(), '')
525
526 result.addSuccess(self)
527 result.stopTest(self)
528
529 self.assertIs(sys.stdout, result._original_stdout)
530 self.assertIs(sys.stderr, result._original_stderr)
531
532 self.assertEqual(result._original_stdout.getvalue(), '')
533 self.assertEqual(result._original_stderr.getvalue(), '')
534
535 self.assertEqual(out_stream.getvalue(), '')
536 self.assertEqual(err_stream.getvalue(), '')
537
538
539 def getStartedResult(self):
540 result = unittest.TestResult()
541 result.buffer = True
542 result.startTest(self)
543 return result
544
545 def testBufferOutputAddErrorOrFailure(self):
Michael Foordd23ea062010-05-02 21:00:22 +0000546 unittest.result.traceback = MockTraceback
547 self.addCleanup(restore_traceback)
548
Benjamin Petersonb48af542010-04-11 20:43:16 +0000549 for message_attr, add_attr, include_error in [
550 ('errors', 'addError', True),
551 ('failures', 'addFailure', False),
552 ('errors', 'addError', True),
553 ('failures', 'addFailure', False)
554 ]:
555 result = self.getStartedResult()
556 buffered_out = sys.stdout
557 buffered_err = sys.stderr
558 result._original_stdout = io.StringIO()
559 result._original_stderr = io.StringIO()
560
561 print('foo', file=sys.stdout)
562 if include_error:
563 print('bar', file=sys.stderr)
564
565
566 addFunction = getattr(result, add_attr)
567 addFunction(self, (None, None, None))
568 result.stopTest(self)
569
570 result_list = getattr(result, message_attr)
571 self.assertEqual(len(result_list), 1)
572
573 test, message = result_list[0]
574 expectedOutMessage = textwrap.dedent("""
575 Stdout:
576 foo
577 """)
578 expectedErrMessage = ''
579 if include_error:
580 expectedErrMessage = textwrap.dedent("""
581 Stderr:
582 bar
583 """)
Michael Foordd23ea062010-05-02 21:00:22 +0000584
585 expectedFullMessage = 'A traceback%s%s' % (expectedOutMessage, expectedErrMessage)
Benjamin Petersonb48af542010-04-11 20:43:16 +0000586
587 self.assertIs(test, self)
588 self.assertEqual(result._original_stdout.getvalue(), expectedOutMessage)
589 self.assertEqual(result._original_stderr.getvalue(), expectedErrMessage)
590 self.assertMultiLineEqual(message, expectedFullMessage)
591
Michael Foord42ec7cb2011-03-17 13:44:18 -0400592 def testBufferSetupClass(self):
593 result = unittest.TestResult()
594 result.buffer = True
595
596 class Foo(unittest.TestCase):
597 @classmethod
598 def setUpClass(cls):
599 1/0
600 def test_foo(self):
601 pass
602 suite = unittest.TestSuite([Foo('test_foo')])
603 suite(result)
604 self.assertEqual(len(result.errors), 1)
605
606 def testBufferTearDownClass(self):
607 result = unittest.TestResult()
608 result.buffer = True
609
610 class Foo(unittest.TestCase):
611 @classmethod
612 def tearDownClass(cls):
613 1/0
614 def test_foo(self):
615 pass
616 suite = unittest.TestSuite([Foo('test_foo')])
617 suite(result)
618 self.assertEqual(len(result.errors), 1)
619
620 def testBufferSetUpModule(self):
621 result = unittest.TestResult()
622 result.buffer = True
623
624 class Foo(unittest.TestCase):
625 def test_foo(self):
626 pass
627 class Module(object):
628 @staticmethod
629 def setUpModule():
630 1/0
631
632 Foo.__module__ = 'Module'
633 sys.modules['Module'] = Module
634 self.addCleanup(sys.modules.pop, 'Module')
635 suite = unittest.TestSuite([Foo('test_foo')])
636 suite(result)
637 self.assertEqual(len(result.errors), 1)
638
639 def testBufferTearDownModule(self):
640 result = unittest.TestResult()
641 result.buffer = True
642
643 class Foo(unittest.TestCase):
644 def test_foo(self):
645 pass
646 class Module(object):
647 @staticmethod
648 def tearDownModule():
649 1/0
650
651 Foo.__module__ = 'Module'
652 sys.modules['Module'] = Module
653 self.addCleanup(sys.modules.pop, 'Module')
654 suite = unittest.TestSuite([Foo('test_foo')])
655 suite(result)
656 self.assertEqual(len(result.errors), 1)
657
658
Benjamin Petersonb48af542010-04-11 20:43:16 +0000659if __name__ == '__main__':
660 unittest.main()