blob: 9aa79b31d21f403b1ba27a90474ffac688a2697a [file] [log] [blame]
Fred Drake02538202001-03-21 18:09:46 +00001#!/usr/bin/env python
Steve Purcell5ddd1a82001-03-22 08:45:36 +00002'''
Fred Drake02538202001-03-21 18:09:46 +00003Python unit testing framework, based on Erich Gamma's JUnit and Kent Beck's
4Smalltalk testing framework.
5
Fred Drake02538202001-03-21 18:09:46 +00006This module contains the core framework classes that form the basis of
7specific test cases and suites (TestCase, TestSuite etc.), and also a
8text-based utility class for running the tests and reporting the results
9(TextTestRunner).
10
Steve Purcell5ddd1a82001-03-22 08:45:36 +000011Simple 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)
Steve Purcell7b065702001-09-06 08:24:40 +000019 def testMultiply(self):
Steve Purcell5ddd1a82001-03-22 08:45:36 +000020 self.assertEquals((0 * 10), 0)
21 self.assertEquals((5 * 8), 40)
22
23 if __name__ == '__main__':
24 unittest.main()
25
26Further information is available in the bundled documentation, and from
27
28 http://pyunit.sourceforge.net/
29
Fred Drake02538202001-03-21 18:09:46 +000030Copyright (c) 1999, 2000, 2001 Steve Purcell
31This module is free software, and you may redistribute it and/or modify
32it under the same terms as Python itself, so long as this copyright message
33and disclaimer are retained in their original form.
34
35IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
36SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
37THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
38DAMAGE.
39
40THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
41LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
42PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
43AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
44SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
Steve Purcell5ddd1a82001-03-22 08:45:36 +000045'''
Fred Drake02538202001-03-21 18:09:46 +000046
Steve Purcell5ddd1a82001-03-22 08:45:36 +000047__author__ = "Steve Purcell"
48__email__ = "stephen_purcell at yahoo dot com"
Fred Drake02538202001-03-21 18:09:46 +000049__version__ = "$Revision$"[11:-2]
50
51import time
52import sys
53import traceback
54import string
55import os
Steve Purcell5ddd1a82001-03-22 08:45:36 +000056import types
Fred Drake02538202001-03-21 18:09:46 +000057
58##############################################################################
59# Test framework core
60##############################################################################
61
62class TestResult:
63 """Holder for test result information.
64
65 Test results are automatically managed by the TestCase and TestSuite
66 classes, and do not need to be explicitly manipulated by writers of tests.
67
68 Each instance holds the total number of tests run, and collections of
69 failures and errors that occurred among those test runs. The collections
Steve Purcell7b065702001-09-06 08:24:40 +000070 contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
71 formatted traceback of the error that occurred
Fred Drake02538202001-03-21 18:09:46 +000072 """
73 def __init__(self):
74 self.failures = []
75 self.errors = []
76 self.testsRun = 0
77 self.shouldStop = 0
78
79 def startTest(self, test):
80 "Called when the given test is about to be run"
81 self.testsRun = self.testsRun + 1
82
83 def stopTest(self, test):
84 "Called when the given test has been run"
85 pass
86
87 def addError(self, test, err):
Steve Purcell7b065702001-09-06 08:24:40 +000088 """Called when an error has occurred. 'err' is a tuple of values as
89 returned by sys.exc_info().
90 """
91 self.errors.append((test, self._exc_info_to_string(err)))
Fred Drake02538202001-03-21 18:09:46 +000092
93 def addFailure(self, test, err):
Steve Purcell7b065702001-09-06 08:24:40 +000094 """Called when an error has occurred. 'err' is a tuple of values as
95 returned by sys.exc_info()."""
96 self.failures.append((test, self._exc_info_to_string(err)))
Fred Drake02538202001-03-21 18:09:46 +000097
Steve Purcell5ddd1a82001-03-22 08:45:36 +000098 def addSuccess(self, test):
99 "Called when a test has completed successfully"
100 pass
101
Fred Drake02538202001-03-21 18:09:46 +0000102 def wasSuccessful(self):
103 "Tells whether or not this result was a success"
104 return len(self.failures) == len(self.errors) == 0
105
106 def stop(self):
107 "Indicates that the tests should be aborted"
108 self.shouldStop = 1
Tim Petersa19a1682001-03-29 04:36:09 +0000109
Steve Purcell7b065702001-09-06 08:24:40 +0000110 def _exc_info_to_string(self, err):
111 """Converts a sys.exc_info()-style tuple of values into a string."""
112 return string.join(apply(traceback.format_exception, err), '')
113
Fred Drake02538202001-03-21 18:09:46 +0000114 def __repr__(self):
115 return "<%s run=%i errors=%i failures=%i>" % \
116 (self.__class__, self.testsRun, len(self.errors),
117 len(self.failures))
118
119
120class TestCase:
121 """A class whose instances are single test cases.
122
Fred Drake02538202001-03-21 18:09:46 +0000123 By default, the test code itself should be placed in a method named
124 'runTest'.
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000125
Tim Petersa19a1682001-03-29 04:36:09 +0000126 If the fixture may be used for many test cases, create as
Fred Drake02538202001-03-21 18:09:46 +0000127 many test methods as are needed. When instantiating such a TestCase
128 subclass, specify in the constructor arguments the name of the test method
129 that the instance is to execute.
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000130
Tim Petersa19a1682001-03-29 04:36:09 +0000131 Test authors should subclass TestCase for their own tests. Construction
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000132 and deconstruction of the test's environment ('fixture') can be
133 implemented by overriding the 'setUp' and 'tearDown' methods respectively.
134
135 If it is necessary to override the __init__ method, the base class
136 __init__ method must always be called. It is important that subclasses
137 should not change the signature of their __init__ method, since instances
138 of the classes are instantiated automatically by parts of the framework
139 in order to be run.
Fred Drake02538202001-03-21 18:09:46 +0000140 """
Steve Purcell15d89272001-04-12 09:05:01 +0000141
142 # This attribute determines which exception will be raised when
143 # the instance's assertion methods fail; test methods raising this
144 # exception will be deemed to have 'failed' rather than 'errored'
145
146 failureException = AssertionError
147
Fred Drake02538202001-03-21 18:09:46 +0000148 def __init__(self, methodName='runTest'):
149 """Create an instance of the class that will use the named test
150 method when executed. Raises a ValueError if the instance does
151 not have a method with the specified name.
152 """
153 try:
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000154 self.__testMethodName = methodName
155 testMethod = getattr(self, methodName)
156 self.__testMethodDoc = testMethod.__doc__
Fred Drake02538202001-03-21 18:09:46 +0000157 except AttributeError:
158 raise ValueError, "no such test method in %s: %s" % \
159 (self.__class__, methodName)
160
161 def setUp(self):
162 "Hook method for setting up the test fixture before exercising it."
163 pass
164
165 def tearDown(self):
166 "Hook method for deconstructing the test fixture after testing it."
167 pass
168
169 def countTestCases(self):
170 return 1
171
172 def defaultTestResult(self):
173 return TestResult()
174
175 def shortDescription(self):
176 """Returns a one-line description of the test, or None if no
177 description has been provided.
178
179 The default implementation of this method returns the first line of
180 the specified test method's docstring.
181 """
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000182 doc = self.__testMethodDoc
Fred Drake02538202001-03-21 18:09:46 +0000183 return doc and string.strip(string.split(doc, "\n")[0]) or None
184
185 def id(self):
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000186 return "%s.%s" % (self.__class__, self.__testMethodName)
Fred Drake02538202001-03-21 18:09:46 +0000187
188 def __str__(self):
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000189 return "%s (%s)" % (self.__testMethodName, self.__class__)
Fred Drake02538202001-03-21 18:09:46 +0000190
191 def __repr__(self):
192 return "<%s testMethod=%s>" % \
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000193 (self.__class__, self.__testMethodName)
Fred Drake02538202001-03-21 18:09:46 +0000194
195 def run(self, result=None):
196 return self(result)
197
198 def __call__(self, result=None):
199 if result is None: result = self.defaultTestResult()
200 result.startTest(self)
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000201 testMethod = getattr(self, self.__testMethodName)
Fred Drake02538202001-03-21 18:09:46 +0000202 try:
203 try:
204 self.setUp()
205 except:
Steve Purcell15d89272001-04-12 09:05:01 +0000206 result.addError(self,self.__exc_info())
Fred Drake02538202001-03-21 18:09:46 +0000207 return
208
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000209 ok = 0
Fred Drake02538202001-03-21 18:09:46 +0000210 try:
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000211 testMethod()
212 ok = 1
Steve Purcell15d89272001-04-12 09:05:01 +0000213 except self.failureException, e:
214 result.addFailure(self,self.__exc_info())
Fred Drake02538202001-03-21 18:09:46 +0000215 except:
Steve Purcell15d89272001-04-12 09:05:01 +0000216 result.addError(self,self.__exc_info())
Fred Drake02538202001-03-21 18:09:46 +0000217
218 try:
219 self.tearDown()
220 except:
Steve Purcell15d89272001-04-12 09:05:01 +0000221 result.addError(self,self.__exc_info())
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000222 ok = 0
223 if ok: result.addSuccess(self)
Fred Drake02538202001-03-21 18:09:46 +0000224 finally:
225 result.stopTest(self)
226
227 def debug(self):
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000228 """Run the test without collecting errors in a TestResult"""
Fred Drake02538202001-03-21 18:09:46 +0000229 self.setUp()
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000230 getattr(self, self.__testMethodName)()
Fred Drake02538202001-03-21 18:09:46 +0000231 self.tearDown()
232
Steve Purcell15d89272001-04-12 09:05:01 +0000233 def __exc_info(self):
234 """Return a version of sys.exc_info() with the traceback frame
235 minimised; usually the top level of the traceback frame is not
236 needed.
Fred Drake02538202001-03-21 18:09:46 +0000237 """
Steve Purcell15d89272001-04-12 09:05:01 +0000238 exctype, excvalue, tb = sys.exc_info()
239 if sys.platform[:4] == 'java': ## tracebacks look different in Jython
240 return (exctype, excvalue, tb)
241 newtb = tb.tb_next
242 if newtb is None:
243 return (exctype, excvalue, tb)
244 return (exctype, excvalue, newtb)
Fred Drake02538202001-03-21 18:09:46 +0000245
Steve Purcell15d89272001-04-12 09:05:01 +0000246 def fail(self, msg=None):
247 """Fail immediately, with the given message."""
248 raise self.failureException, msg
Fred Drake02538202001-03-21 18:09:46 +0000249
250 def failIf(self, expr, msg=None):
251 "Fail the test if the expression is true."
Steve Purcell15d89272001-04-12 09:05:01 +0000252 if expr: raise self.failureException, msg
Fred Drake02538202001-03-21 18:09:46 +0000253
Steve Purcell15d89272001-04-12 09:05:01 +0000254 def failUnless(self, expr, msg=None):
255 """Fail the test unless the expression is true."""
256 if not expr: raise self.failureException, msg
257
258 def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
259 """Fail unless an exception of class excClass is thrown
Fred Drake02538202001-03-21 18:09:46 +0000260 by callableObj when invoked with arguments args and keyword
261 arguments kwargs. If a different type of exception is
262 thrown, it will not be caught, and the test case will be
263 deemed to have suffered an error, exactly as for an
264 unexpected exception.
265 """
266 try:
267 apply(callableObj, args, kwargs)
268 except excClass:
269 return
270 else:
271 if hasattr(excClass,'__name__'): excName = excClass.__name__
272 else: excName = str(excClass)
Steve Purcell15d89272001-04-12 09:05:01 +0000273 raise self.failureException, excName
Fred Drake02538202001-03-21 18:09:46 +0000274
Steve Purcell15d89272001-04-12 09:05:01 +0000275 def failUnlessEqual(self, first, second, msg=None):
276 """Fail if the two objects are unequal as determined by the '!='
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000277 operator.
278 """
Steve Purcell15d89272001-04-12 09:05:01 +0000279 if first != second:
280 raise self.failureException, (msg or '%s != %s' % (first, second))
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000281
Steve Purcell15d89272001-04-12 09:05:01 +0000282 def failIfEqual(self, first, second, msg=None):
283 """Fail if the two objects are equal as determined by the '=='
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000284 operator.
285 """
Steve Purcell15d89272001-04-12 09:05:01 +0000286 if first == second:
Steve Purcellab0648f2001-04-15 09:18:32 +0000287 raise self.failureException, (msg or '%s == %s' % (first, second))
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000288
Steve Purcell15d89272001-04-12 09:05:01 +0000289 assertEqual = assertEquals = failUnlessEqual
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000290
Steve Purcell15d89272001-04-12 09:05:01 +0000291 assertNotEqual = assertNotEquals = failIfEqual
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000292
Steve Purcell15d89272001-04-12 09:05:01 +0000293 assertRaises = failUnlessRaises
294
295 assert_ = failUnless
296
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000297
Fred Drake02538202001-03-21 18:09:46 +0000298
299class TestSuite:
300 """A test suite is a composite test consisting of a number of TestCases.
301
302 For use, create an instance of TestSuite, then add test case instances.
303 When all tests have been added, the suite can be passed to a test
304 runner, such as TextTestRunner. It will run the individual test cases
305 in the order in which they were added, aggregating the results. When
306 subclassing, do not forget to call the base class constructor.
307 """
308 def __init__(self, tests=()):
309 self._tests = []
310 self.addTests(tests)
311
312 def __repr__(self):
313 return "<%s tests=%s>" % (self.__class__, self._tests)
314
315 __str__ = __repr__
316
317 def countTestCases(self):
318 cases = 0
319 for test in self._tests:
320 cases = cases + test.countTestCases()
321 return cases
322
323 def addTest(self, test):
324 self._tests.append(test)
325
326 def addTests(self, tests):
327 for test in tests:
328 self.addTest(test)
329
330 def run(self, result):
331 return self(result)
332
333 def __call__(self, result):
334 for test in self._tests:
335 if result.shouldStop:
336 break
337 test(result)
338 return result
339
340 def debug(self):
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000341 """Run the tests without collecting errors in a TestResult"""
Fred Drake02538202001-03-21 18:09:46 +0000342 for test in self._tests: test.debug()
Fred Drake02538202001-03-21 18:09:46 +0000343
344
345class FunctionTestCase(TestCase):
346 """A test case that wraps a test function.
347
348 This is useful for slipping pre-existing test functions into the
349 PyUnit framework. Optionally, set-up and tidy-up functions can be
350 supplied. As with TestCase, the tidy-up ('tearDown') function will
351 always be called if the set-up ('setUp') function ran successfully.
352 """
353
354 def __init__(self, testFunc, setUp=None, tearDown=None,
355 description=None):
356 TestCase.__init__(self)
357 self.__setUpFunc = setUp
358 self.__tearDownFunc = tearDown
359 self.__testFunc = testFunc
360 self.__description = description
361
362 def setUp(self):
363 if self.__setUpFunc is not None:
364 self.__setUpFunc()
365
366 def tearDown(self):
367 if self.__tearDownFunc is not None:
368 self.__tearDownFunc()
369
370 def runTest(self):
371 self.__testFunc()
372
373 def id(self):
374 return self.__testFunc.__name__
375
376 def __str__(self):
377 return "%s (%s)" % (self.__class__, self.__testFunc.__name__)
378
379 def __repr__(self):
380 return "<%s testFunc=%s>" % (self.__class__, self.__testFunc)
381
382 def shortDescription(self):
383 if self.__description is not None: return self.__description
384 doc = self.__testFunc.__doc__
385 return doc and string.strip(string.split(doc, "\n")[0]) or None
386
387
388
389##############################################################################
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000390# Locating and loading tests
Fred Drake02538202001-03-21 18:09:46 +0000391##############################################################################
392
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000393class TestLoader:
394 """This class is responsible for loading tests according to various
395 criteria and returning them wrapped in a Test
Fred Drake02538202001-03-21 18:09:46 +0000396 """
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000397 testMethodPrefix = 'test'
398 sortTestMethodsUsing = cmp
399 suiteClass = TestSuite
Fred Drake02538202001-03-21 18:09:46 +0000400
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000401 def loadTestsFromTestCase(self, testCaseClass):
Steve Purcell15d89272001-04-12 09:05:01 +0000402 """Return a suite of all tests cases contained in testCaseClass"""
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000403 return self.suiteClass(map(testCaseClass,
404 self.getTestCaseNames(testCaseClass)))
Fred Drake02538202001-03-21 18:09:46 +0000405
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000406 def loadTestsFromModule(self, module):
Steve Purcell15d89272001-04-12 09:05:01 +0000407 """Return a suite of all tests cases contained in the given module"""
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000408 tests = []
409 for name in dir(module):
410 obj = getattr(module, name)
411 if type(obj) == types.ClassType and issubclass(obj, TestCase):
412 tests.append(self.loadTestsFromTestCase(obj))
413 return self.suiteClass(tests)
Fred Drake02538202001-03-21 18:09:46 +0000414
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000415 def loadTestsFromName(self, name, module=None):
Steve Purcell15d89272001-04-12 09:05:01 +0000416 """Return a suite of all tests cases given a string specifier.
417
418 The name may resolve either to a module, a test case class, a
419 test method within a test case class, or a callable object which
420 returns a TestCase or TestSuite instance.
Tim Peters613b2222001-04-13 05:37:27 +0000421
Steve Purcell15d89272001-04-12 09:05:01 +0000422 The method optionally resolves the names relative to a given module.
423 """
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000424 parts = string.split(name, '.')
425 if module is None:
426 if not parts:
427 raise ValueError, "incomplete test name: %s" % name
428 else:
Steve Purcell17a781b2001-04-09 15:37:31 +0000429 parts_copy = parts[:]
430 while parts_copy:
431 try:
432 module = __import__(string.join(parts_copy,'.'))
433 break
434 except ImportError:
435 del parts_copy[-1]
436 if not parts_copy: raise
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000437 parts = parts[1:]
438 obj = module
439 for part in parts:
440 obj = getattr(obj, part)
Fred Drake02538202001-03-21 18:09:46 +0000441
Steve Purcelle00dde22001-08-08 07:57:26 +0000442 import unittest
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000443 if type(obj) == types.ModuleType:
444 return self.loadTestsFromModule(obj)
Steve Purcelle00dde22001-08-08 07:57:26 +0000445 elif type(obj) == types.ClassType and issubclass(obj, unittest.TestCase):
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000446 return self.loadTestsFromTestCase(obj)
447 elif type(obj) == types.UnboundMethodType:
448 return obj.im_class(obj.__name__)
449 elif callable(obj):
450 test = obj()
Steve Purcelle00dde22001-08-08 07:57:26 +0000451 if not isinstance(test, unittest.TestCase) and \
452 not isinstance(test, unittest.TestSuite):
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000453 raise ValueError, \
Steve Purcell4bc80852001-05-10 01:28:40 +0000454 "calling %s returned %s, not a test" % (obj,test)
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000455 return test
Fred Drake02538202001-03-21 18:09:46 +0000456 else:
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000457 raise ValueError, "don't know how to make test from: %s" % obj
458
459 def loadTestsFromNames(self, names, module=None):
Steve Purcell15d89272001-04-12 09:05:01 +0000460 """Return a suite of all tests cases found using the given sequence
461 of string specifiers. See 'loadTestsFromName()'.
462 """
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000463 suites = []
464 for name in names:
465 suites.append(self.loadTestsFromName(name, module))
466 return self.suiteClass(suites)
467
468 def getTestCaseNames(self, testCaseClass):
Steve Purcell15d89272001-04-12 09:05:01 +0000469 """Return a sorted sequence of method names found within testCaseClass
470 """
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000471 testFnNames = filter(lambda n,p=self.testMethodPrefix: n[:len(p)] == p,
472 dir(testCaseClass))
473 for baseclass in testCaseClass.__bases__:
474 for testFnName in self.getTestCaseNames(baseclass):
475 if testFnName not in testFnNames: # handle overridden methods
476 testFnNames.append(testFnName)
477 if self.sortTestMethodsUsing:
478 testFnNames.sort(self.sortTestMethodsUsing)
479 return testFnNames
480
481
482
483defaultTestLoader = TestLoader()
484
485
486##############################################################################
487# Patches for old functions: these functions should be considered obsolete
488##############################################################################
489
490def _makeLoader(prefix, sortUsing, suiteClass=None):
491 loader = TestLoader()
492 loader.sortTestMethodsUsing = sortUsing
493 loader.testMethodPrefix = prefix
494 if suiteClass: loader.suiteClass = suiteClass
495 return loader
496
497def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp):
498 return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass)
499
500def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
501 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass)
502
503def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
504 return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module)
Fred Drake02538202001-03-21 18:09:46 +0000505
506
507##############################################################################
508# Text UI
509##############################################################################
510
511class _WritelnDecorator:
512 """Used to decorate file-like objects with a handy 'writeln' method"""
513 def __init__(self,stream):
514 self.stream = stream
Fred Drake02538202001-03-21 18:09:46 +0000515
516 def __getattr__(self, attr):
517 return getattr(self.stream,attr)
518
519 def writeln(self, *args):
520 if args: apply(self.write, args)
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000521 self.write('\n') # text-mode streams translate to \r\n if needed
Tim Petersa19a1682001-03-29 04:36:09 +0000522
Fred Drake02538202001-03-21 18:09:46 +0000523
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000524class _TextTestResult(TestResult):
Fred Drake02538202001-03-21 18:09:46 +0000525 """A test result class that can print formatted text results to a stream.
526
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000527 Used by TextTestRunner.
Fred Drake02538202001-03-21 18:09:46 +0000528 """
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000529 separator1 = '=' * 70
530 separator2 = '-' * 70
Fred Drake02538202001-03-21 18:09:46 +0000531
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000532 def __init__(self, stream, descriptions, verbosity):
Fred Drake02538202001-03-21 18:09:46 +0000533 TestResult.__init__(self)
534 self.stream = stream
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000535 self.showAll = verbosity > 1
536 self.dots = verbosity == 1
Fred Drake02538202001-03-21 18:09:46 +0000537 self.descriptions = descriptions
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000538
539 def getDescription(self, test):
540 if self.descriptions:
541 return test.shortDescription() or str(test)
542 else:
543 return str(test)
544
Fred Drake02538202001-03-21 18:09:46 +0000545 def startTest(self, test):
546 TestResult.startTest(self, test)
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000547 if self.showAll:
548 self.stream.write(self.getDescription(test))
549 self.stream.write(" ... ")
Fred Drake02538202001-03-21 18:09:46 +0000550
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000551 def addSuccess(self, test):
552 TestResult.addSuccess(self, test)
553 if self.showAll:
Fred Drake02538202001-03-21 18:09:46 +0000554 self.stream.writeln("ok")
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000555 elif self.dots:
556 self.stream.write('.')
Fred Drake02538202001-03-21 18:09:46 +0000557
558 def addError(self, test, err):
559 TestResult.addError(self, test, err)
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000560 if self.showAll:
561 self.stream.writeln("ERROR")
562 elif self.dots:
563 self.stream.write('E')
Fred Drake02538202001-03-21 18:09:46 +0000564 if err[0] is KeyboardInterrupt:
565 self.shouldStop = 1
566
567 def addFailure(self, test, err):
568 TestResult.addFailure(self, test, err)
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000569 if self.showAll:
570 self.stream.writeln("FAIL")
571 elif self.dots:
572 self.stream.write('F')
Fred Drake02538202001-03-21 18:09:46 +0000573
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000574 def printErrors(self):
575 if self.dots or self.showAll:
Fred Drake02538202001-03-21 18:09:46 +0000576 self.stream.writeln()
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000577 self.printErrorList('ERROR', self.errors)
578 self.printErrorList('FAIL', self.failures)
579
580 def printErrorList(self, flavour, errors):
581 for test, err in errors:
582 self.stream.writeln(self.separator1)
583 self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
584 self.stream.writeln(self.separator2)
Steve Purcell7b065702001-09-06 08:24:40 +0000585 self.stream.writeln("%s" % err)
Fred Drake02538202001-03-21 18:09:46 +0000586
587
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000588class TextTestRunner:
Fred Drake02538202001-03-21 18:09:46 +0000589 """A test runner class that displays results in textual form.
Tim Petersa19a1682001-03-29 04:36:09 +0000590
Fred Drake02538202001-03-21 18:09:46 +0000591 It prints out the names of tests as they are run, errors as they
592 occur, and a summary of the results at the end of the test run.
593 """
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000594 def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1):
Fred Drake02538202001-03-21 18:09:46 +0000595 self.stream = _WritelnDecorator(stream)
596 self.descriptions = descriptions
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000597 self.verbosity = verbosity
598
599 def _makeResult(self):
600 return _TextTestResult(self.stream, self.descriptions, self.verbosity)
Fred Drake02538202001-03-21 18:09:46 +0000601
602 def run(self, test):
603 "Run the given test case or test suite."
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000604 result = self._makeResult()
Fred Drake02538202001-03-21 18:09:46 +0000605 startTime = time.time()
606 test(result)
607 stopTime = time.time()
608 timeTaken = float(stopTime - startTime)
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000609 result.printErrors()
610 self.stream.writeln(result.separator2)
Fred Drake02538202001-03-21 18:09:46 +0000611 run = result.testsRun
612 self.stream.writeln("Ran %d test%s in %.3fs" %
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000613 (run, run == 1 and "" or "s", timeTaken))
Fred Drake02538202001-03-21 18:09:46 +0000614 self.stream.writeln()
615 if not result.wasSuccessful():
616 self.stream.write("FAILED (")
617 failed, errored = map(len, (result.failures, result.errors))
618 if failed:
619 self.stream.write("failures=%d" % failed)
620 if errored:
621 if failed: self.stream.write(", ")
622 self.stream.write("errors=%d" % errored)
623 self.stream.writeln(")")
624 else:
625 self.stream.writeln("OK")
626 return result
Tim Petersa19a1682001-03-29 04:36:09 +0000627
Fred Drake02538202001-03-21 18:09:46 +0000628
Fred Drake02538202001-03-21 18:09:46 +0000629
630##############################################################################
631# Facilities for running tests from the command line
632##############################################################################
633
634class TestProgram:
635 """A command-line program that runs a set of tests; this is primarily
636 for making test modules conveniently executable.
637 """
638 USAGE = """\
Steve Purcell17a781b2001-04-09 15:37:31 +0000639Usage: %(progName)s [options] [test] [...]
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000640
641Options:
642 -h, --help Show this message
643 -v, --verbose Verbose output
644 -q, --quiet Minimal output
Fred Drake02538202001-03-21 18:09:46 +0000645
646Examples:
647 %(progName)s - run default set of tests
648 %(progName)s MyTestSuite - run suite 'MyTestSuite'
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000649 %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething
650 %(progName)s MyTestCase - run all 'test*' test methods
Fred Drake02538202001-03-21 18:09:46 +0000651 in MyTestCase
652"""
653 def __init__(self, module='__main__', defaultTest=None,
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000654 argv=None, testRunner=None, testLoader=defaultTestLoader):
Fred Drake02538202001-03-21 18:09:46 +0000655 if type(module) == type(''):
656 self.module = __import__(module)
657 for part in string.split(module,'.')[1:]:
658 self.module = getattr(self.module, part)
659 else:
660 self.module = module
661 if argv is None:
662 argv = sys.argv
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000663 self.verbosity = 1
Fred Drake02538202001-03-21 18:09:46 +0000664 self.defaultTest = defaultTest
665 self.testRunner = testRunner
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000666 self.testLoader = testLoader
Fred Drake02538202001-03-21 18:09:46 +0000667 self.progName = os.path.basename(argv[0])
668 self.parseArgs(argv)
Fred Drake02538202001-03-21 18:09:46 +0000669 self.runTests()
670
671 def usageExit(self, msg=None):
672 if msg: print msg
673 print self.USAGE % self.__dict__
674 sys.exit(2)
675
676 def parseArgs(self, argv):
677 import getopt
678 try:
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000679 options, args = getopt.getopt(argv[1:], 'hHvq',
680 ['help','verbose','quiet'])
Fred Drake02538202001-03-21 18:09:46 +0000681 for opt, value in options:
682 if opt in ('-h','-H','--help'):
683 self.usageExit()
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000684 if opt in ('-q','--quiet'):
685 self.verbosity = 0
686 if opt in ('-v','--verbose'):
687 self.verbosity = 2
Fred Drake02538202001-03-21 18:09:46 +0000688 if len(args) == 0 and self.defaultTest is None:
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000689 self.test = self.testLoader.loadTestsFromModule(self.module)
690 return
Fred Drake02538202001-03-21 18:09:46 +0000691 if len(args) > 0:
692 self.testNames = args
693 else:
694 self.testNames = (self.defaultTest,)
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000695 self.createTests()
Fred Drake02538202001-03-21 18:09:46 +0000696 except getopt.error, msg:
697 self.usageExit(msg)
698
699 def createTests(self):
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000700 self.test = self.testLoader.loadTestsFromNames(self.testNames,
701 self.module)
Fred Drake02538202001-03-21 18:09:46 +0000702
703 def runTests(self):
704 if self.testRunner is None:
Steve Purcell5ddd1a82001-03-22 08:45:36 +0000705 self.testRunner = TextTestRunner(verbosity=self.verbosity)
Fred Drake02538202001-03-21 18:09:46 +0000706 result = self.testRunner.run(self.test)
Tim Petersa19a1682001-03-29 04:36:09 +0000707 sys.exit(not result.wasSuccessful())
Fred Drake02538202001-03-21 18:09:46 +0000708
709main = TestProgram
710
711
712##############################################################################
713# Executing this module from the command line
714##############################################################################
715
716if __name__ == "__main__":
717 main(module=None)