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