Statistics
| Revision:

root / tags / v1_0_2_Build_915 / extensions / extScripting / scripts / jython / Lib / unittest.py @ 12217

History | View | Annotate | Download (24.3 KB)

1 5782 jmvivo
#!/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, 2000, 2001 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$"[11:-2]
50
51
import time
52
import sys
53
import traceback
54
import string
55
import os
56
import types
57
58
##############################################################################
59
# Test framework core
60
##############################################################################
61
62
class 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
70
    contain tuples of (testcase, exceptioninfo), where exceptioninfo is a
71
    tuple of values as returned by sys.exc_info().
72
    """
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):
88
        "Called when an error has occurred"
89
        self.errors.append((test, err))
90
91
    def addFailure(self, test, err):
92
        "Called when a failure has occurred"
93
        self.failures.append((test, err))
94
95
    def addSuccess(self, test):
96
        "Called when a test has completed successfully"
97
        pass
98
99
    def wasSuccessful(self):
100
        "Tells whether or not this result was a success"
101
        return len(self.failures) == len(self.errors) == 0
102
103
    def stop(self):
104
        "Indicates that the tests should be aborted"
105
        self.shouldStop = 1
106
107
    def __repr__(self):
108
        return "<%s run=%i errors=%i failures=%i>" % \
109
               (self.__class__, self.testsRun, len(self.errors),
110
                len(self.failures))
111
112
113
class TestCase:
114
    """A class whose instances are single test cases.
115

116
    By default, the test code itself should be placed in a method named
117
    'runTest'.
118

119
    If the fixture may be used for many test cases, create as
120
    many test methods as are needed. When instantiating such a TestCase
121
    subclass, specify in the constructor arguments the name of the test method
122
    that the instance is to execute.
123

124
    Test authors should subclass TestCase for their own tests. Construction
125
    and deconstruction of the test's environment ('fixture') can be
126
    implemented by overriding the 'setUp' and 'tearDown' methods respectively.
127

128
    If it is necessary to override the __init__ method, the base class
129
    __init__ method must always be called. It is important that subclasses
130
    should not change the signature of their __init__ method, since instances
131
    of the classes are instantiated automatically by parts of the framework
132
    in order to be run.
133
    """
134
135
    # This attribute determines which exception will be raised when
136
    # the instance's assertion methods fail; test methods raising this
137
    # exception will be deemed to have 'failed' rather than 'errored'
138
139
    failureException = AssertionError
140
141
    def __init__(self, methodName='runTest'):
142
        """Create an instance of the class that will use the named test
143
           method when executed. Raises a ValueError if the instance does
144
           not have a method with the specified name.
145
        """
146
        try:
147
            self.__testMethodName = methodName
148
            testMethod = getattr(self, methodName)
149
            self.__testMethodDoc = testMethod.__doc__
150
        except AttributeError:
151
            raise ValueError, "no such test method in %s: %s" % \
152
                  (self.__class__, methodName)
153
154
    def setUp(self):
155
        "Hook method for setting up the test fixture before exercising it."
156
        pass
157
158
    def tearDown(self):
159
        "Hook method for deconstructing the test fixture after testing it."
160
        pass
161
162
    def countTestCases(self):
163
        return 1
164
165
    def defaultTestResult(self):
166
        return TestResult()
167
168
    def shortDescription(self):
169
        """Returns a one-line description of the test, or None if no
170
        description has been provided.
171

172
        The default implementation of this method returns the first line of
173
        the specified test method's docstring.
174
        """
175
        doc = self.__testMethodDoc
176
        return doc and string.strip(string.split(doc, "\n")[0]) or None
177
178
    def id(self):
179
        return "%s.%s" % (self.__class__, self.__testMethodName)
180
181
    def __str__(self):
182
        return "%s (%s)" % (self.__testMethodName, self.__class__)
183
184
    def __repr__(self):
185
        return "<%s testMethod=%s>" % \
186
               (self.__class__, self.__testMethodName)
187
188
    def run(self, result=None):
189
        return self(result)
190
191
    def __call__(self, result=None):
192
        if result is None: result = self.defaultTestResult()
193
        result.startTest(self)
194
        testMethod = getattr(self, self.__testMethodName)
195
        try:
196
            try:
197
                self.setUp()
198
            except:
199
                result.addError(self,self.__exc_info())
200
                return
201
202
            ok = 0
203
            try:
204
                testMethod()
205
                ok = 1
206
            except self.failureException, e:
207
                result.addFailure(self,self.__exc_info())
208
            except:
209
                result.addError(self,self.__exc_info())
210
211
            try:
212
                self.tearDown()
213
            except:
214
                result.addError(self,self.__exc_info())
215
                ok = 0
216
            if ok: result.addSuccess(self)
217
        finally:
218
            result.stopTest(self)
219
220
    def debug(self):
221
        """Run the test without collecting errors in a TestResult"""
222
        self.setUp()
223
        getattr(self, self.__testMethodName)()
224
        self.tearDown()
225
226
    def __exc_info(self):
227
        """Return a version of sys.exc_info() with the traceback frame
228
           minimised; usually the top level of the traceback frame is not
229
           needed.
230
        """
231
        exctype, excvalue, tb = sys.exc_info()
232
        if sys.platform[:4] == 'java': ## tracebacks look different in Jython
233
            return (exctype, excvalue, tb)
234
        newtb = tb.tb_next
235
        if newtb is None:
236
            return (exctype, excvalue, tb)
237
        return (exctype, excvalue, newtb)
238
239
    def fail(self, msg=None):
240
        """Fail immediately, with the given message."""
241
        raise self.failureException, msg
242
243
    def failIf(self, expr, msg=None):
244
        "Fail the test if the expression is true."
245
        if expr: raise self.failureException, msg
246
247
    def failUnless(self, expr, msg=None):
248
        """Fail the test unless the expression is true."""
249
        if not expr: raise self.failureException, msg
250
251
    def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
252
        """Fail unless an exception of class excClass is thrown
253
           by callableObj when invoked with arguments args and keyword
254
           arguments kwargs. If a different type of exception is
255
           thrown, it will not be caught, and the test case will be
256
           deemed to have suffered an error, exactly as for an
257
           unexpected exception.
258
        """
259
        try:
260
            apply(callableObj, args, kwargs)
261
        except excClass:
262
            return
263
        else:
264
            if hasattr(excClass,'__name__'): excName = excClass.__name__
265
            else: excName = str(excClass)
266
            raise self.failureException, excName
267
268
    def failUnlessEqual(self, first, second, msg=None):
269
        """Fail if the two objects are unequal as determined by the '!='
270
           operator.
271
        """
272
        if first != second:
273
            raise self.failureException, (msg or '%s != %s' % (first, second))
274
275
    def failIfEqual(self, first, second, msg=None):
276
        """Fail if the two objects are equal as determined by the '=='
277
           operator.
278
        """
279
        if first == second:
280
            raise self.failureException, (msg or '%s == %s' % (first, second))
281
282
    assertEqual = assertEquals = failUnlessEqual
283
284
    assertNotEqual = assertNotEquals = failIfEqual
285
286
    assertRaises = failUnlessRaises
287
288
    assert_ = failUnless
289
290
291
292
class TestSuite:
293
    """A test suite is a composite test consisting of a number of TestCases.
294

295
    For use, create an instance of TestSuite, then add test case instances.
296
    When all tests have been added, the suite can be passed to a test
297
    runner, such as TextTestRunner. It will run the individual test cases
298
    in the order in which they were added, aggregating the results. When
299
    subclassing, do not forget to call the base class constructor.
300
    """
301
    def __init__(self, tests=()):
302
        self._tests = []
303
        self.addTests(tests)
304
305
    def __repr__(self):
306
        return "<%s tests=%s>" % (self.__class__, self._tests)
307
308
    __str__ = __repr__
309
310
    def countTestCases(self):
311
        cases = 0
312
        for test in self._tests:
313
            cases = cases + test.countTestCases()
314
        return cases
315
316
    def addTest(self, test):
317
        self._tests.append(test)
318
319
    def addTests(self, tests):
320
        for test in tests:
321
            self.addTest(test)
322
323
    def run(self, result):
324
        return self(result)
325
326
    def __call__(self, result):
327
        for test in self._tests:
328
            if result.shouldStop:
329
                break
330
            test(result)
331
        return result
332
333
    def debug(self):
334
        """Run the tests without collecting errors in a TestResult"""
335
        for test in self._tests: test.debug()
336
337
338
class FunctionTestCase(TestCase):
339
    """A test case that wraps a test function.
340

341
    This is useful for slipping pre-existing test functions into the
342
    PyUnit framework. Optionally, set-up and tidy-up functions can be
343
    supplied. As with TestCase, the tidy-up ('tearDown') function will
344
    always be called if the set-up ('setUp') function ran successfully.
345
    """
346
347
    def __init__(self, testFunc, setUp=None, tearDown=None,
348
                 description=None):
349
        TestCase.__init__(self)
350
        self.__setUpFunc = setUp
351
        self.__tearDownFunc = tearDown
352
        self.__testFunc = testFunc
353
        self.__description = description
354
355
    def setUp(self):
356
        if self.__setUpFunc is not None:
357
            self.__setUpFunc()
358
359
    def tearDown(self):
360
        if self.__tearDownFunc is not None:
361
            self.__tearDownFunc()
362
363
    def runTest(self):
364
        self.__testFunc()
365
366
    def id(self):
367
        return self.__testFunc.__name__
368
369
    def __str__(self):
370
        return "%s (%s)" % (self.__class__, self.__testFunc.__name__)
371
372
    def __repr__(self):
373
        return "<%s testFunc=%s>" % (self.__class__, self.__testFunc)
374
375
    def shortDescription(self):
376
        if self.__description is not None: return self.__description
377
        doc = self.__testFunc.__doc__
378
        return doc and string.strip(string.split(doc, "\n")[0]) or None
379
380
381
382
##############################################################################
383
# Locating and loading tests
384
##############################################################################
385
386
class TestLoader:
387
    """This class is responsible for loading tests according to various
388
    criteria and returning them wrapped in a Test
389
    """
390
    testMethodPrefix = 'test'
391
    sortTestMethodsUsing = cmp
392
    suiteClass = TestSuite
393
394
    def loadTestsFromTestCase(self, testCaseClass):
395
        """Return a suite of all tests cases contained in testCaseClass"""
396
        return self.suiteClass(map(testCaseClass,
397
                                   self.getTestCaseNames(testCaseClass)))
398
399
    def loadTestsFromModule(self, module):
400
        """Return a suite of all tests cases contained in the given module"""
401
        tests = []
402
        for name in dir(module):
403
            obj = getattr(module, name)
404
            if type(obj) == types.ClassType and issubclass(obj, TestCase):
405
                tests.append(self.loadTestsFromTestCase(obj))
406
        return self.suiteClass(tests)
407
408
    def loadTestsFromName(self, name, module=None):
409
        """Return a suite of all tests cases given a string specifier.
410

411
        The name may resolve either to a module, a test case class, a
412
        test method within a test case class, or a callable object which
413
        returns a TestCase or TestSuite instance.
414

415
        The method optionally resolves the names relative to a given module.
416
        """
417
        parts = string.split(name, '.')
418
        if module is None:
419
            if not parts:
420
                raise ValueError, "incomplete test name: %s" % name
421
            else:
422
                parts_copy = parts[:]
423
                while parts_copy:
424
                    try:
425
                        module = __import__(string.join(parts_copy,'.'))
426
                        break
427
                    except ImportError:
428
                        del parts_copy[-1]
429
                        if not parts_copy: raise
430
                parts = parts[1:]
431
        obj = module
432
        for part in parts:
433
            obj = getattr(obj, part)
434
435
        if type(obj) == types.ModuleType:
436
            return self.loadTestsFromModule(obj)
437
        elif type(obj) == types.ClassType and issubclass(obj, TestCase):
438
            return self.loadTestsFromTestCase(obj)
439
        elif type(obj) == types.UnboundMethodType:
440
            return obj.im_class(obj.__name__)
441
        elif callable(obj):
442
            test = obj()
443
            if not isinstance(test, TestCase) and \
444
               not isinstance(test, TestSuite):
445
                raise ValueError, \
446
                      "calling %s returned %s, not a test" % obj,test
447
            return test
448
        else:
449
            raise ValueError, "don't know how to make test from: %s" % obj
450
451
    def loadTestsFromNames(self, names, module=None):
452
        """Return a suite of all tests cases found using the given sequence
453
        of string specifiers. See 'loadTestsFromName()'.
454
        """
455
        suites = []
456
        for name in names:
457
            suites.append(self.loadTestsFromName(name, module))
458
        return self.suiteClass(suites)
459
460
    def getTestCaseNames(self, testCaseClass):
461
        """Return a sorted sequence of method names found within testCaseClass
462
        """
463
        testFnNames = filter(lambda n,p=self.testMethodPrefix: n[:len(p)] == p,
464
                             dir(testCaseClass))
465
        for baseclass in testCaseClass.__bases__:
466
            for testFnName in self.getTestCaseNames(baseclass):
467
                if testFnName not in testFnNames:  # handle overridden methods
468
                    testFnNames.append(testFnName)
469
        if self.sortTestMethodsUsing:
470
            testFnNames.sort(self.sortTestMethodsUsing)
471
        return testFnNames
472
473
474
475
defaultTestLoader = TestLoader()
476
477
478
##############################################################################
479
# Patches for old functions: these functions should be considered obsolete
480
##############################################################################
481
482
def _makeLoader(prefix, sortUsing, suiteClass=None):
483
    loader = TestLoader()
484
    loader.sortTestMethodsUsing = sortUsing
485
    loader.testMethodPrefix = prefix
486
    if suiteClass: loader.suiteClass = suiteClass
487
    return loader
488
489
def getTestCaseNames(testCaseClass, prefix, sortUsing=cmp):
490
    return _makeLoader(prefix, sortUsing).getTestCaseNames(testCaseClass)
491
492
def makeSuite(testCaseClass, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
493
    return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromTestCase(testCaseClass)
494
495
def findTestCases(module, prefix='test', sortUsing=cmp, suiteClass=TestSuite):
496
    return _makeLoader(prefix, sortUsing, suiteClass).loadTestsFromModule(module)
497
498
499
##############################################################################
500
# Text UI
501
##############################################################################
502
503
class _WritelnDecorator:
504
    """Used to decorate file-like objects with a handy 'writeln' method"""
505
    def __init__(self,stream):
506
        self.stream = stream
507
508
    def __getattr__(self, attr):
509
        return getattr(self.stream,attr)
510
511
    def writeln(self, *args):
512
        if args: apply(self.write, args)
513
        self.write('\n') # text-mode streams translate to \r\n if needed
514
515
516
class _TextTestResult(TestResult):
517
    """A test result class that can print formatted text results to a stream.
518

519
    Used by TextTestRunner.
520
    """
521
    separator1 = '=' * 70
522
    separator2 = '-' * 70
523
524
    def __init__(self, stream, descriptions, verbosity):
525
        TestResult.__init__(self)
526
        self.stream = stream
527
        self.showAll = verbosity > 1
528
        self.dots = verbosity == 1
529
        self.descriptions = descriptions
530
531
    def getDescription(self, test):
532
        if self.descriptions:
533
            return test.shortDescription() or str(test)
534
        else:
535
            return str(test)
536
537
    def startTest(self, test):
538
        TestResult.startTest(self, test)
539
        if self.showAll:
540
            self.stream.write(self.getDescription(test))
541
            self.stream.write(" ... ")
542
543
    def addSuccess(self, test):
544
        TestResult.addSuccess(self, test)
545
        if self.showAll:
546
            self.stream.writeln("ok")
547
        elif self.dots:
548
            self.stream.write('.')
549
550
    def addError(self, test, err):
551
        TestResult.addError(self, test, err)
552
        if self.showAll:
553
            self.stream.writeln("ERROR")
554
        elif self.dots:
555
            self.stream.write('E')
556
        if err[0] is KeyboardInterrupt:
557
            self.shouldStop = 1
558
559
    def addFailure(self, test, err):
560
        TestResult.addFailure(self, test, err)
561
        if self.showAll:
562
            self.stream.writeln("FAIL")
563
        elif self.dots:
564
            self.stream.write('F')
565
566
    def printErrors(self):
567
        if self.dots or self.showAll:
568
            self.stream.writeln()
569
        self.printErrorList('ERROR', self.errors)
570
        self.printErrorList('FAIL', self.failures)
571
572
    def printErrorList(self, flavour, errors):
573
        for test, err in errors:
574
            self.stream.writeln(self.separator1)
575
            self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
576
            self.stream.writeln(self.separator2)
577
            for line in apply(traceback.format_exception, err):
578
                for l in string.split(line,"\n")[:-1]:
579
                    self.stream.writeln("%s" % l)
580
581
582
class TextTestRunner:
583
    """A test runner class that displays results in textual form.
584

585
    It prints out the names of tests as they are run, errors as they
586
    occur, and a summary of the results at the end of the test run.
587
    """
588
    def __init__(self, stream=sys.stderr, descriptions=1, verbosity=1):
589
        self.stream = _WritelnDecorator(stream)
590
        self.descriptions = descriptions
591
        self.verbosity = verbosity
592
593
    def _makeResult(self):
594
        return _TextTestResult(self.stream, self.descriptions, self.verbosity)
595
596
    def run(self, test):
597
        "Run the given test case or test suite."
598
        result = self._makeResult()
599
        startTime = time.time()
600
        test(result)
601
        stopTime = time.time()
602
        timeTaken = float(stopTime - startTime)
603
        result.printErrors()
604
        self.stream.writeln(result.separator2)
605
        run = result.testsRun
606
        self.stream.writeln("Ran %d test%s in %.3fs" %
607
                            (run, run == 1 and "" or "s", timeTaken))
608
        self.stream.writeln()
609
        if not result.wasSuccessful():
610
            self.stream.write("FAILED (")
611
            failed, errored = map(len, (result.failures, result.errors))
612
            if failed:
613
                self.stream.write("failures=%d" % failed)
614
            if errored:
615
                if failed: self.stream.write(", ")
616
                self.stream.write("errors=%d" % errored)
617
            self.stream.writeln(")")
618
        else:
619
            self.stream.writeln("OK")
620
        return result
621
622
623
624
##############################################################################
625
# Facilities for running tests from the command line
626
##############################################################################
627
628
class TestProgram:
629
    """A command-line program that runs a set of tests; this is primarily
630
       for making test modules conveniently executable.
631
    """
632
    USAGE = """\
633
Usage: %(progName)s [options] [test] [...]
634

635
Options:
636
  -h, --help       Show this message
637
  -v, --verbose    Verbose output
638
  -q, --quiet      Minimal output
639

640
Examples:
641
  %(progName)s                               - run default set of tests
642
  %(progName)s MyTestSuite                   - run suite 'MyTestSuite'
643
  %(progName)s MyTestCase.testSomething      - run MyTestCase.testSomething
644
  %(progName)s MyTestCase                    - run all 'test*' test methods
645
                                               in MyTestCase
646
"""
647
    def __init__(self, module='__main__', defaultTest=None,
648
                 argv=None, testRunner=None, testLoader=defaultTestLoader):
649
        if type(module) == type(''):
650
            self.module = __import__(module)
651
            for part in string.split(module,'.')[1:]:
652
                self.module = getattr(self.module, part)
653
        else:
654
            self.module = module
655
        if argv is None:
656
            argv = sys.argv
657
        self.verbosity = 1
658
        self.defaultTest = defaultTest
659
        self.testRunner = testRunner
660
        self.testLoader = testLoader
661
        self.progName = os.path.basename(argv[0])
662
        self.parseArgs(argv)
663
        self.runTests()
664
665
    def usageExit(self, msg=None):
666
        if msg: print msg
667
        print self.USAGE % self.__dict__
668
        sys.exit(2)
669
670
    def parseArgs(self, argv):
671
        import getopt
672
        try:
673
            options, args = getopt.getopt(argv[1:], 'hHvq',
674
                                          ['help','verbose','quiet'])
675
            for opt, value in options:
676
                if opt in ('-h','-H','--help'):
677
                    self.usageExit()
678
                if opt in ('-q','--quiet'):
679
                    self.verbosity = 0
680
                if opt in ('-v','--verbose'):
681
                    self.verbosity = 2
682
            if len(args) == 0 and self.defaultTest is None:
683
                self.test = self.testLoader.loadTestsFromModule(self.module)
684
                return
685
            if len(args) > 0:
686
                self.testNames = args
687
            else:
688
                self.testNames = (self.defaultTest,)
689
            self.createTests()
690
        except getopt.error, msg:
691
            self.usageExit(msg)
692
693
    def createTests(self):
694
        self.test = self.testLoader.loadTestsFromNames(self.testNames,
695
                                                       self.module)
696
697
    def runTests(self):
698
        if self.testRunner is None:
699
            self.testRunner = TextTestRunner(verbosity=self.verbosity)
700
        result = self.testRunner.run(self.test)
701
        sys.exit(not result.wasSuccessful())
702
703
main = TestProgram
704
705
706
##############################################################################
707
# Executing this module from the command line
708
##############################################################################
709
710
if __name__ == "__main__":
711
    main(module=None)