|
1 #!/usr/bin/env python |
|
2 ''' |
|
3 Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's |
|
4 Smalltalk testing framework. |
|
5 |
|
6 This module contains the core framework classes that form the basis of |
|
7 specific test cases and suites (TestCase, TestSuite etc.), and also a |
|
8 text-based utility class for running the tests and reporting the results |
|
9 (TextTestRunner). |
|
10 |
|
11 Simple usage: |
|
12 |
|
13 import unittest |
|
14 |
|
15 class IntegerArithmenticTestCase(unittest.TestCase): |
|
16 def testAdd(self): ## test method names begin 'test*' |
|
17 self.assertEquals((1 + 2), 3) |
|
18 self.assertEquals(0 + 1, 1) |
|
19 def testMultiply(self): |
|
20 self.assertEquals((0 * 10), 0) |
|
21 self.assertEquals((5 * 8), 40) |
|
22 |
|
23 if __name__ == '__main__': |
|
24 unittest.main() |
|
25 |
|
26 Further information is available in the bundled documentation, and from |
|
27 |
|
28 http://docs.python.org/lib/module-unittest.html |
|
29 |
|
30 Copyright (c) 1999-2003 Steve Purcell |
|
31 This module is free software, and you may redistribute it and/or modify |
|
32 it under the same terms as Python itself, so long as this copyright message |
|
33 and disclaimer are retained in their original form. |
|
34 |
|
35 IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, |
|
36 SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF |
|
37 THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
|
38 DAMAGE. |
|
39 |
|
40 THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT |
|
41 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A |
|
42 PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, |
|
43 AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, |
|
44 SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
|
45 ''' |
|
46 |
|
47 __author__ = "Steve Purcell" |
|
48 __email__ = "stephen_purcell at yahoo dot com" |
|
49 __version__ = "#Revision: 1.63 $"[11:-2] |
|
50 |
|
51 import time |
|
52 import sys |
|
53 import traceback |
|
54 import os |
|
55 import types |
|
56 |
|
57 ############################################################################## |
|
58 # Exported classes and functions |
|
59 ############################################################################## |
|
60 __all__ = ['TestResult', 'TestCase', 'TestSuite', 'TextTestRunner', |
|
61 'TestLoader', 'FunctionTestCase', 'main', 'defaultTestLoader'] |
|
62 |
|
63 # Expose obsolete functions for backwards compatibility |
|
64 __all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases']) |
|
65 |
|
66 |
|
67 ############################################################################## |
|
68 # Backward compatibility |
|
69 ############################################################################## |
|
70 if sys.version_info[:2] < (2, 2): |
|
71 def isinstance(obj, clsinfo): |
|
72 import __builtin__ |
|
73 if type(clsinfo) in (tuple, list): |
|
74 for cls in clsinfo: |
|
75 if cls is type: cls = types.ClassType |
|
76 if __builtin__.isinstance(obj, cls): |
|
77 return 1 |
|
78 return 0 |
|
79 else: return __builtin__.isinstance(obj, clsinfo) |
|
80 |
|
81 def _CmpToKey(mycmp): |
|
82 'Convert a cmp= function into a key= function' |
|
83 class K(object): |
|
84 def __init__(self, obj): |
|
85 self.obj = obj |
|
86 def __lt__(self, other): |
|
87 return mycmp(self.obj, other.obj) == -1 |
|
88 return K |
|
89 |
|
90 ############################################################################## |
|
91 # Test framework core |
|
92 ############################################################################## |
|
93 |
|
94 # All classes defined herein are 'new-style' classes, allowing use of 'super()' |
|
95 __metaclass__ = type |
|
96 |
|
97 def _strclass(cls): |
|
98 return "%s.%s" % (cls.__module__, cls.__name__) |
|
99 |
|
100 __unittest = 1 |
|
101 |
|
102 class TestResult: |
|
103 """Holder for test result information. |
|
104 |
|
105 Test results are automatically managed by the TestCase and TestSuite |
|
106 classes, and do not need to be explicitly manipulated by writers of tests. |
|
107 |
|
108 Each instance holds the total number of tests run, and collections of |
|
109 failures and errors that occurred among those test runs. The collections |
|
110 contain tuples of (testcase, exceptioninfo), where exceptioninfo is the |
|
111 formatted traceback of the error that occurred. |
|
112 """ |
|
113 def __init__(self): |
|
114 self.failures = [] |
|
115 self.errors = [] |
|
116 self.testsRun = 0 |
|
117 self.shouldStop = False |
|
118 |
|
119 def startTest(self, test): |
|
120 "Called when the given test is about to be run" |
|
121 self.testsRun = self.testsRun + 1 |
|
122 |
|
123 def stopTest(self, test): |
|
124 "Called when the given test has been run" |
|
125 pass |
|
126 |
|
127 def addError(self, test, err): |
|
128 """Called when an error has occurred. 'err' is a tuple of values as |
|
129 returned by sys.exc_info(). |
|
130 """ |
|
131 self.errors.append((test, self._exc_info_to_string(err, test))) |
|
132 |
|
133 def addFailure(self, test, err): |
|
134 """Called when an error has occurred. 'err' is a tuple of values as |
|
135 returned by sys.exc_info().""" |
|
136 self.failures.append((test, self._exc_info_to_string(err, test))) |
|
137 |
|
138 def addSuccess(self, test): |
|
139 "Called when a test has completed successfully" |
|
140 pass |
|
141 |
|
142 def wasSuccessful(self): |
|
143 "Tells whether or not this result was a success" |
|
144 return len(self.failures) == len(self.errors) == 0 |
|
145 |
|
146 def stop(self): |
|
147 "Indicates that the tests should be aborted" |
|
148 self.shouldStop = True |
|
149 |
|
150 def _exc_info_to_string(self, err, test): |
|
151 """Converts a sys.exc_info()-style tuple of values into a string.""" |
|
152 exctype, value, tb = err |
|
153 # Skip test runner traceback levels |
|
154 while tb and self._is_relevant_tb_level(tb): |
|
155 tb = tb.tb_next |
|
156 if exctype is test.failureException: |
|
157 # Skip assert*() traceback levels |
|
158 length = self._count_relevant_tb_levels(tb) |
|
159 return ''.join(traceback.format_exception(exctype, value, tb, length)) |
|
160 return ''.join(traceback.format_exception(exctype, value, tb)) |
|
161 |
|
162 def _is_relevant_tb_level(self, tb): |
|
163 return '__unittest' in tb.tb_frame.f_globals |
|
164 |
|
165 def _count_relevant_tb_levels(self, tb): |
|
166 length = 0 |
|
167 while tb and not self._is_relevant_tb_level(tb): |
|
168 length += 1 |
|
169 tb = tb.tb_next |
|
170 return length |
|
171 |
|
172 def __repr__(self): |
|
173 return "<%s run=%i errors=%i failures=%i>" % \ |
|
174 (_strclass(self.__class__), self.testsRun, len(self.errors), |
|
175 len(self.failures)) |
|
176 |
|
177 class TestCase: |
|
178 """A class whose instances are single test cases. |
|
179 |
|
180 By default, the test code itself should be placed in a method named |
|
181 'runTest'. |
|
182 |
|
183 If the fixture may be used for many test cases, create as |
|
184 many test methods as are needed. When instantiating such a TestCase |
|
185 subclass, specify in the constructor arguments the name of the test method |
|
186 that the instance is to execute. |
|
187 |
|
188 Test authors should subclass TestCase for their own tests. Construction |
|
189 and deconstruction of the test's environment ('fixture') can be |
|
190 implemented by overriding the 'setUp' and 'tearDown' methods respectively. |
|
191 |
|
192 If it is necessary to override the __init__ method, the base class |
|
193 __init__ method must always be called. It is important that subclasses |
|
194 should not change the signature of their __init__ method, since instances |
|
195 of the classes are instantiated automatically by parts of the framework |
|
196 in order to be run. |
|
197 """ |
|
198 |
|
199 # This attribute determines which exception will be raised when |
|
200 # the instance's assertion methods fail; test methods raising this |
|
201 # exception will be deemed to have 'failed' rather than 'errored' |
|
202 |
|
203 failureException = AssertionError |
|
204 |
|
205 def __init__(self, methodName='runTest'): |
|
206 """Create an instance of the class that will use the named test |
|
207 method when executed. Raises a ValueError if the instance does |
|
208 not have a method with the specified name. |
|
209 """ |
|
210 try: |
|
211 self._testMethodName = methodName |
|
212 testMethod = getattr(self, methodName) |
|
213 self._testMethodDoc = testMethod.__doc__ |
|
214 except AttributeError: |
|
215 raise ValueError, "no such test method in %s: %s" % \ |
|
216 (self.__class__, methodName) |
|
217 |
|
218 def setUp(self): |
|
219 "Hook method for setting up the test fixture before exercising it." |
|
220 pass |
|
221 |
|
222 def tearDown(self): |
|
223 "Hook method for deconstructing the test fixture after testing it." |
|
224 pass |
|
225 |
|
226 def countTestCases(self): |
|
227 return 1 |
|
228 |
|
229 def defaultTestResult(self): |
|
230 return TestResult() |
|
231 |
|
232 def shortDescription(self): |
|
233 """Returns a one-line description of the test, or None if no |
|
234 description has been provided. |
|
235 |
|
236 The default implementation of this method returns the first line of |
|
237 the specified test method's docstring. |
|
238 """ |
|
239 doc = self._testMethodDoc |
|
240 return doc and doc.split("\n")[0].strip() or None |
|
241 |
|
242 def id(self): |
|
243 return "%s.%s" % (_strclass(self.__class__), self._testMethodName) |
|
244 |
|
245 def __eq__(self, other): |
|
246 if type(self) is not type(other): |
|
247 return False |
|
248 |
|
249 return self._testMethodName == other._testMethodName |
|
250 |
|
251 def __ne__(self, other): |
|
252 return not self == other |
|
253 |
|
254 def __hash__(self): |
|
255 return hash((type(self), self._testMethodName)) |
|
256 |
|
257 def __str__(self): |
|
258 return "%s (%s)" % (self._testMethodName, _strclass(self.__class__)) |
|
259 |
|
260 def __repr__(self): |
|
261 return "<%s testMethod=%s>" % \ |
|
262 (_strclass(self.__class__), self._testMethodName) |
|
263 |
|
264 def run(self, result=None): |
|
265 if result is None: result = self.defaultTestResult() |
|
266 result.startTest(self) |
|
267 testMethod = getattr(self, self._testMethodName) |
|
268 try: |
|
269 try: |
|
270 self.setUp() |
|
271 except KeyboardInterrupt: |
|
272 raise |
|
273 except: |
|
274 result.addError(self, self._exc_info()) |
|
275 return |
|
276 |
|
277 ok = False |
|
278 try: |
|
279 testMethod() |
|
280 ok = True |
|
281 except self.failureException: |
|
282 result.addFailure(self, self._exc_info()) |
|
283 except KeyboardInterrupt: |
|
284 raise |
|
285 except: |
|
286 result.addError(self, self._exc_info()) |
|
287 |
|
288 try: |
|
289 self.tearDown() |
|
290 except KeyboardInterrupt: |
|
291 raise |
|
292 except: |
|
293 result.addError(self, self._exc_info()) |
|
294 ok = False |
|
295 if ok: result.addSuccess(self) |
|
296 finally: |
|
297 result.stopTest(self) |
|
298 |
|
299 def __call__(self, *args, **kwds): |
|
300 return self.run(*args, **kwds) |
|
301 |
|
302 def debug(self): |
|
303 """Run the test without collecting errors in a TestResult""" |
|
304 self.setUp() |
|
305 getattr(self, self._testMethodName)() |
|
306 self.tearDown() |
|
307 |
|
308 def _exc_info(self): |
|
309 """Return a version of sys.exc_info() with the traceback frame |
|
310 minimised; usually the top level of the traceback frame is not |
|
311 needed. |
|
312 """ |
|
313 return sys.exc_info() |
|
314 |
|
315 def fail(self, msg=None): |
|
316 """Fail immediately, with the given message.""" |
|
317 raise self.failureException, msg |
|
318 |
|
319 def failIf(self, expr, msg=None): |
|
320 "Fail the test if the expression is true." |
|
321 if expr: raise self.failureException, msg |
|
322 |
|
323 def failUnless(self, expr, msg=None): |
|
324 """Fail the test unless the expression is true.""" |
|
325 if not expr: raise self.failureException, msg |
|
326 |
|
327 def failUnlessRaises(self, excClass, callableObj, *args, **kwargs): |
|
328 """Fail unless an exception of class excClass is thrown |
|
329 by callableObj when invoked with arguments args and keyword |
|
330 arguments kwargs. If a different type of exception is |
|
331 thrown, it will not be caught, and the test case will be |
|
332 deemed to have suffered an error, exactly as for an |
|
333 unexpected exception. |
|
334 """ |
|
335 try: |
|
336 callableObj(*args, **kwargs) |
|
337 except excClass: |
|
338 return |
|
339 else: |
|
340 if hasattr(excClass,'__name__'): excName = excClass.__name__ |
|
341 else: excName = str(excClass) |
|
342 raise self.failureException, "%s not raised" % excName |
|
343 |
|
344 def failUnlessEqual(self, first, second, msg=None): |
|
345 """Fail if the two objects are unequal as determined by the '==' |
|
346 operator. |
|
347 """ |
|
348 if not first == second: |
|
349 raise self.failureException, \ |
|
350 (msg or '%r != %r' % (first, second)) |
|
351 |
|
352 def failIfEqual(self, first, second, msg=None): |
|
353 """Fail if the two objects are equal as determined by the '==' |
|
354 operator. |
|
355 """ |
|
356 if first == second: |
|
357 raise self.failureException, \ |
|
358 (msg or '%r == %r' % (first, second)) |
|
359 |
|
360 def failUnlessAlmostEqual(self, first, second, places=7, msg=None): |
|
361 """Fail if the two objects are unequal as determined by their |
|
362 difference rounded to the given number of decimal places |
|
363 (default 7) and comparing to zero. |
|
364 |
|
365 Note that decimal places (from zero) are usually not the same |
|
366 as significant digits (measured from the most signficant digit). |
|
367 """ |
|
368 if round(abs(second-first), places) != 0: |
|
369 raise self.failureException, \ |
|
370 (msg or '%r != %r within %r places' % (first, second, places)) |
|
371 |
|
372 def failIfAlmostEqual(self, first, second, places=7, msg=None): |
|
373 """Fail if the two objects are equal as determined by their |
|
374 difference rounded to the given number of decimal places |
|
375 (default 7) and comparing to zero. |
|
376 |
|
377 Note that decimal places (from zero) are usually not the same |
|
378 as significant digits (measured from the most signficant digit). |
|
379 """ |
|
380 if round(abs(second-first), places) == 0: |
|
381 raise self.failureException, \ |
|
382 (msg or '%r == %r within %r places' % (first, second, places)) |
|
383 |
|
384 # Synonyms for assertion methods |
|
385 |
|
386 assertEqual = assertEquals = failUnlessEqual |
|
387 |
|
388 assertNotEqual = assertNotEquals = failIfEqual |
|
389 |
|
390 assertAlmostEqual = assertAlmostEquals = failUnlessAlmostEqual |
|
391 |
|
392 assertNotAlmostEqual = assertNotAlmostEquals = failIfAlmostEqual |
|
393 |
|
394 assertRaises = failUnlessRaises |
|
395 |
|
396 assert_ = assertTrue = failUnless |
|
397 |
|
398 assertFalse = failIf |
|
399 |
|
400 |
|
401 |
|
402 class TestSuite: |
|
403 """A test suite is a composite test consisting of a number of TestCases. |
|
404 |
|
405 For use, create an instance of TestSuite, then add test case instances. |
|
406 When all tests have been added, the suite can be passed to a test |
|
407 runner, such as TextTestRunner. It will run the individual test cases |
|
408 in the order in which they were added, aggregating the results. When |
|
409 subclassing, do not forget to call the base class constructor. |
|
410 """ |
|
411 def __init__(self, tests=()): |
|
412 self._tests = [] |
|
413 self.addTests(tests) |
|
414 |
|
415 def __repr__(self): |
|
416 return "<%s tests=%s>" % (_strclass(self.__class__), self._tests) |
|
417 |
|
418 __str__ = __repr__ |
|
419 |
|
420 def __eq__(self, other): |
|
421 if type(self) is not type(other): |
|
422 return False |
|
423 return self._tests == other._tests |
|
424 |
|
425 def __ne__(self, other): |
|
426 return not self == other |
|
427 |
|
428 # Can't guarantee hash invariant, so flag as unhashable |
|
429 __hash__ = None |
|
430 |
|
431 def __iter__(self): |
|
432 return iter(self._tests) |
|
433 |
|
434 def countTestCases(self): |
|
435 cases = 0 |
|
436 for test in self._tests: |
|
437 cases += test.countTestCases() |
|
438 return cases |
|
439 |
|
440 def addTest(self, test): |
|
441 # sanity checks |
|
442 if not hasattr(test, '__call__'): |
|
443 raise TypeError("the test to add must be callable") |
|
444 if (isinstance(test, (type, types.ClassType)) and |
|
445 issubclass(test, (TestCase, TestSuite))): |
|
446 raise TypeError("TestCases and TestSuites must be instantiated " |
|
447 "before passing them to addTest()") |
|
448 self._tests.append(test) |
|
449 |
|
450 def addTests(self, tests): |
|
451 if isinstance(tests, basestring): |
|
452 raise TypeError("tests must be an iterable of tests, not a string") |
|
453 for test in tests: |
|
454 self.addTest(test) |
|
455 |
|
456 def run(self, result): |
|
457 for test in self._tests: |
|
458 if result.shouldStop: |
|
459 break |
|
460 test(result) |
|
461 return result |
|
462 |
|
463 def __call__(self, *args, **kwds): |
|
464 return self.run(*args, **kwds) |
|
465 |
|
466 def debug(self): |
|
467 """Run the tests without collecting errors in a TestResult""" |
|
468 for test in self._tests: test.debug() |
|
469 |
|
470 |
|
471 class FunctionTestCase(TestCase): |
|
472 """A test case that wraps a test function. |
|
473 |
|
474 This is useful for slipping pre-existing test functions into the |
|
475 unittest framework. Optionally, set-up and tidy-up functions can be |
|
476 supplied. As with TestCase, the tidy-up ('tearDown') function will |
|
477 always be called if the set-up ('setUp') function ran successfully. |
|
478 """ |
|
479 |
|
480 def __init__(self, testFunc, setUp=None, tearDown=None, |
|
481 description=None): |
|
482 TestCase.__init__(self) |
|
483 self.__setUpFunc = setUp |
|
484 self.__tearDownFunc = tearDown |
|
485 self.__testFunc = testFunc |
|
486 self.__description = description |
|
487 |
|
488 def setUp(self): |
|
489 if self.__setUpFunc is not None: |
|
490 self.__setUpFunc() |
|
491 |
|
492 def tearDown(self): |
|
493 if self.__tearDownFunc is not None: |
|
494 self.__tearDownFunc() |
|
495 |
|
496 def runTest(self): |
|
497 self.__testFunc() |
|
498 |
|
499 def id(self): |
|
500 return self.__testFunc.__name__ |
|
501 |
|
502 def __eq__(self, other): |
|
503 if type(self) is not type(other): |
|
504 return False |
|
505 |
|
506 return self.__setUpFunc == other.__setUpFunc and \ |
|
507 self.__tearDownFunc == other.__tearDownFunc and \ |
|
508 self.__testFunc == other.__testFunc and \ |
|
509 self.__description == other.__description |
|
510 |
|
511 def __ne__(self, other): |
|
512 return not self == other |
|
513 |
|
514 def __hash__(self): |
|
515 return hash((type(self), self.__setUpFunc, self.__tearDownFunc, |
|
516 self.__testFunc, self.__description)) |
|
517 |
|
518 def __str__(self): |
|
519 return "%s (%s)" % (_strclass(self.__class__), self.__testFunc.__name__) |
|
520 |
|
521 def __repr__(self): |
|
522 return "<%s testFunc=%s>" % (_strclass(self.__class__), self.__testFunc) |
|
523 |
|
524 def shortDescription(self): |
|
525 if self.__description is not None: return self.__description |
|
526 doc = self.__testFunc.__doc__ |
|
527 return doc and doc.split("\n")[0].strip() or None |
|
528 |
|
529 |
|
530 |
|
531 ############################################################################## |
|
532 # Locating and loading tests |
|
533 ############################################################################## |
|
534 |
|
535 class TestLoader: |
|
536 """This class is responsible for loading tests according to various |
|
537 criteria and returning them wrapped in a TestSuite |
|
538 """ |
|
539 testMethodPrefix = 'test' |
|
540 sortTestMethodsUsing = cmp |
|
541 suiteClass = TestSuite |
|
542 |
|
543 def loadTestsFromTestCase(self, testCaseClass): |
|
544 """Return a suite of all tests cases contained in testCaseClass""" |
|
545 if issubclass(testCaseClass, TestSuite): |
|
546 raise TypeError("Test cases should not be derived from TestSuite. Maybe you meant to derive from TestCase?") |
|
547 testCaseNames = self.getTestCaseNames(testCaseClass) |
|
548 if not testCaseNames and hasattr(testCaseClass, 'runTest'): |
|
549 testCaseNames = ['runTest'] |
|
550 return self.suiteClass(map(testCaseClass, testCaseNames)) |
|
551 |
|
552 def loadTestsFromModule(self, module): |
|
553 """Return a suite of all tests cases contained in the given module""" |
|
554 tests = [] |
|
555 for name in dir(module): |
|
556 obj = getattr(module, name) |
|
557 if (isinstance(obj, (type, types.ClassType)) and |
|
558 issubclass(obj, TestCase)): |
|
559 tests.append(self.loadTestsFromTestCase(obj)) |
|
560 return self.suiteClass(tests) |
|
561 |
|
562 def loadTestsFromName(self, name, module=None): |
|
563 """Return a suite of all tests cases given a string specifier. |
|
564 |
|
565 The name may resolve either to a module, a test case class, a |
|
566 test method within a test case class, or a callable object which |
|
567 returns a TestCase or TestSuite instance. |
|
568 |
|
569 The method optionally resolves the names relative to a given module. |
|
570 """ |
|
571 parts = name.split('.') |
|
572 if module is None: |
|
573 parts_copy = parts[:] |
|
574 while parts_copy: |
|
575 try: |
|
576 module = __import__('.'.join(parts_copy)) |
|
577 break |
|
578 except ImportError: |
|
579 del parts_copy[-1] |
|
580 if not parts_copy: raise |
|
581 parts = parts[1:] |
|
582 obj = module |
|
583 for part in parts: |
|
584 parent, obj = obj, getattr(obj, part) |
|
585 |
|
586 if type(obj) == types.ModuleType: |
|
587 return self.loadTestsFromModule(obj) |
|
588 elif (isinstance(obj, (type, types.ClassType)) and |
|
589 issubclass(obj, TestCase)): |
|
590 return self.loadTestsFromTestCase(obj) |
|
591 elif (type(obj) == types.UnboundMethodType and |
|
592 isinstance(parent, (type, types.ClassType)) and |
|
593 issubclass(parent, TestCase)): |
|
594 return TestSuite([parent(obj.__name__)]) |
|
595 elif isinstance(obj, TestSuite): |
|
596 return obj |
|
597 elif hasattr(obj, '__call__'): |
|
598 test = obj() |
|
599 if isinstance(test, TestSuite): |
|
600 return test |
|
601 elif isinstance(test, TestCase): |
|
602 return TestSuite([test]) |
|
603 else: |
|
604 raise TypeError("calling %s returned %s, not a test" % |
|
605 (obj, test)) |
|
606 else: |
|
607 raise TypeError("don't know how to make test from: %s" % obj) |
|
608 |
|
609 def loadTestsFromNames(self, names, module=None): |
|
610 """Return a suite of all tests cases found using the given sequence |
|
611 of string specifiers. See 'loadTestsFromName()'. |
|
612 """ |
|
613 suites = [self.loadTestsFromName(name, module) for name in names] |
|
614 return self.suiteClass(suites) |
|
615 |
|
616 def getTestCaseNames(self, testCaseClass): |
|
617 """Return a sorted sequence of method names found within testCaseClass |
|
618 """ |
|
619 def isTestMethod(attrname, testCaseClass=testCaseClass, prefix=self.testMethodPrefix): |
|
620 return attrname.startswith(prefix) and hasattr(getattr(testCaseClass, attrname), '__call__') |
|
621 testFnNames = filter(isTestMethod, dir(testCaseClass)) |
|
622 if self.sortTestMethodsUsing: |
|
623 testFnNames.sort(key=_CmpToKey(self.sortTestMethodsUsing)) |
|
624 return testFnNames |
|
625 |
|
626 |
|
627 |
|
628 defaultTestLoader = TestLoader() |
|
629 |
|
630 |
|
631 ############################################################################## |
|
632 # Patches for old functions: these functions should be considered obsolete |
|
633 ############################################################################## |
|
634 |
|
635 def _makeLoader(prefix, sortUsing, suiteClass=None): |
|
636 loader = TestLoader() |
|
637 loader.sortTestMethodsUsing = sortUsing |
|
638 loader.testMethodPrefix = prefix |
|
639 if suiteClass: loader.suiteClass = suiteClass |
|
640 return loader |
|
641 |
|
642 def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp): |
|
643 return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass) |
|
644 |
|
645 def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite): |
|
646 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass) |
|
647 |
|
648 def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite): |
|
649 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module) |
|
650 |
|
651 |
|
652 ############################################################################## |
|
653 # Text UI |
|
654 ############################################################################## |
|
655 |
|
656 class _WritelnDecorator: |
|
657 """Used to decorate file-like objects with a handy 'writeln' method""" |
|
658 def __init__(self,stream): |
|
659 self.stream = stream |
|
660 |
|
661 def __getattr__(self, attr): |
|
662 return getattr(self.stream,attr) |
|
663 |
|
664 def writeln(self, arg=None): |
|
665 if arg: self.write(arg) |
|
666 self.write('\n') # text-mode streams translate to \r\n if needed |
|
667 |
|
668 |
|
669 class _TextTestResult(TestResult): |
|
670 """A test result class that can print formatted text results to a stream. |
|
671 |
|
672 Used by TextTestRunner. |
|
673 """ |
|
674 separator1 = '=' * 70 |
|
675 separator2 = '-' * 70 |
|
676 |
|
677 def __init__(self, stream, descriptions, verbosity): |
|
678 TestResult.__init__(self) |
|
679 self.stream = stream |
|
680 self.showAll = verbosity > 1 |
|
681 self.dots = verbosity == 1 |
|
682 self.descriptions = descriptions |
|
683 |
|
684 def getDescription(self, test): |
|
685 if self.descriptions: |
|
686 return test.shortDescription() or str(test) |
|
687 else: |
|
688 return str(test) |
|
689 |
|
690 def startTest(self, test): |
|
691 TestResult.startTest(self, test) |
|
692 if self.showAll: |
|
693 self.stream.write(self.getDescription(test)) |
|
694 self.stream.write(" ... ") |
|
695 self.stream.flush() |
|
696 |
|
697 def addSuccess(self, test): |
|
698 TestResult.addSuccess(self, test) |
|
699 if self.showAll: |
|
700 self.stream.writeln("ok") |
|
701 elif self.dots: |
|
702 self.stream.write('.') |
|
703 self.stream.flush() |
|
704 |
|
705 def addError(self, test, err): |
|
706 TestResult.addError(self, test, err) |
|
707 if self.showAll: |
|
708 self.stream.writeln("ERROR") |
|
709 elif self.dots: |
|
710 self.stream.write('E') |
|
711 self.stream.flush() |
|
712 |
|
713 def addFailure(self, test, err): |
|
714 TestResult.addFailure(self, test, err) |
|
715 if self.showAll: |
|
716 self.stream.writeln("FAIL") |
|
717 elif self.dots: |
|
718 self.stream.write('F') |
|
719 self.stream.flush() |
|
720 |
|
721 def printErrors(self): |
|
722 if self.dots or self.showAll: |
|
723 self.stream.writeln() |
|
724 self.printErrorList('ERROR', self.errors) |
|
725 self.printErrorList('FAIL', self.failures) |
|
726 |
|
727 def printErrorList(self, flavour, errors): |
|
728 for test, err in errors: |
|
729 self.stream.writeln(self.separator1) |
|
730 self.stream.writeln("%s: %s" % (flavour,self.getDescription(test))) |
|
731 self.stream.writeln(self.separator2) |
|
732 self.stream.writeln("%s" % err) |
|
733 |
|
734 |
|
735 class TextTestRunner: |
|
736 """A test runner class that displays results in textual form. |
|
737 |
|
738 It prints out the names of tests as they are run, errors as they |
|
739 occur, and a summary of the results at the end of the test run. |
|
740 """ |
|
741 def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1): |
|
742 self.stream = _WritelnDecorator(stream) |
|
743 self.descriptions = descriptions |
|
744 self.verbosity = verbosity |
|
745 |
|
746 def _makeResult(self): |
|
747 return _TextTestResult(self.stream, self.descriptions, self.verbosity) |
|
748 |
|
749 def run(self, test): |
|
750 "Run the given test case or test suite." |
|
751 result = self._makeResult() |
|
752 startTime = time.time() |
|
753 test(result) |
|
754 stopTime = time.time() |
|
755 timeTaken = stopTime - startTime |
|
756 result.printErrors() |
|
757 self.stream.writeln(result.separator2) |
|
758 run = result.testsRun |
|
759 self.stream.writeln("Ran %d test%s in %.3fs" % |
|
760 (run, run != 1 and "s" or "", timeTaken)) |
|
761 self.stream.writeln() |
|
762 if not result.wasSuccessful(): |
|
763 self.stream.write("FAILED (") |
|
764 failed, errored = map(len, (result.failures, result.errors)) |
|
765 if failed: |
|
766 self.stream.write("failures=%d" % failed) |
|
767 if errored: |
|
768 if failed: self.stream.write(", ") |
|
769 self.stream.write("errors=%d" % errored) |
|
770 self.stream.writeln(")") |
|
771 else: |
|
772 self.stream.writeln("OK") |
|
773 return result |
|
774 |
|
775 |
|
776 |
|
777 ############################################################################## |
|
778 # Facilities for running tests from the command line |
|
779 ############################################################################## |
|
780 |
|
781 class TestProgram: |
|
782 """A command-line program that runs a set of tests; this is primarily |
|
783 for making test modules conveniently executable. |
|
784 """ |
|
785 USAGE = """\ |
|
786 Usage: %(progName)s [options] [test] [...] |
|
787 |
|
788 Options: |
|
789 -h, --help Show this message |
|
790 -v, --verbose Verbose output |
|
791 -q, --quiet Minimal output |
|
792 |
|
793 Examples: |
|
794 %(progName)s - run default set of tests |
|
795 %(progName)s MyTestSuite - run suite 'MyTestSuite' |
|
796 %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething |
|
797 %(progName)s MyTestCase - run all 'test*' test methods |
|
798 in MyTestCase |
|
799 """ |
|
800 def __init__(self, module='__main__', defaultTest=None, |
|
801 argv=None, testRunner=TextTestRunner, |
|
802 testLoader=defaultTestLoader): |
|
803 if type(module) == type(''): |
|
804 self.module = __import__(module) |
|
805 for part in module.split('.')[1:]: |
|
806 self.module = getattr(self.module, part) |
|
807 else: |
|
808 self.module = module |
|
809 if argv is None: |
|
810 argv = sys.argv |
|
811 self.verbosity = 1 |
|
812 self.defaultTest = defaultTest |
|
813 self.testRunner = testRunner |
|
814 self.testLoader = testLoader |
|
815 self.progName = os.path.basename(argv[0]) |
|
816 self.parseArgs(argv) |
|
817 self.runTests() |
|
818 |
|
819 def usageExit(self, msg=None): |
|
820 if msg: print msg |
|
821 print self.USAGE % self.__dict__ |
|
822 sys.exit(2) |
|
823 |
|
824 def parseArgs(self, argv): |
|
825 import getopt |
|
826 try: |
|
827 options, args = getopt.getopt(argv[1:], 'hHvq', |
|
828 ['help','verbose','quiet']) |
|
829 for opt, value in options: |
|
830 if opt in ('-h','-H','--help'): |
|
831 self.usageExit() |
|
832 if opt in ('-q','--quiet'): |
|
833 self.verbosity = 0 |
|
834 if opt in ('-v','--verbose'): |
|
835 self.verbosity = 2 |
|
836 if len(args) == 0 and self.defaultTest is None: |
|
837 self.test = self.testLoader.loadTestsFromModule(self.module) |
|
838 return |
|
839 if len(args) > 0: |
|
840 self.testNames = args |
|
841 else: |
|
842 self.testNames = (self.defaultTest,) |
|
843 self.createTests() |
|
844 except getopt.error, msg: |
|
845 self.usageExit(msg) |
|
846 |
|
847 def createTests(self): |
|
848 self.test = self.testLoader.loadTestsFromNames(self.testNames, |
|
849 self.module) |
|
850 |
|
851 def runTests(self): |
|
852 if isinstance(self.testRunner, (type, types.ClassType)): |
|
853 try: |
|
854 testRunner = self.testRunner(verbosity=self.verbosity) |
|
855 except TypeError: |
|
856 # didn't accept the verbosity argument |
|
857 testRunner = self.testRunner() |
|
858 else: |
|
859 # it is assumed to be a TestRunner instance |
|
860 testRunner = self.testRunner |
|
861 result = testRunner.run(self.test) |
|
862 sys.exit(not result.wasSuccessful()) |
|
863 |
|
864 main = TestProgram |
|
865 |
|
866 |
|
867 ############################################################################## |
|
868 # Executing this module from the command line |
|
869 ############################################################################## |
|
870 |
|
871 if __name__ == "__main__": |
|
872 main(module=None) |