This commit is contained in:
Michael Foord 2009-05-02 22:43:34 +00:00
parent 7430989cda
commit 07ef487a96
5 changed files with 257 additions and 39 deletions

View file

@ -6,6 +6,7 @@ Still need testing:
TestCase.{assert,fail}* methods (some are tested implicitly)
"""
from StringIO import StringIO
import re
from test import test_support
import unittest
@ -26,10 +27,18 @@ class LoggingResult(unittest.TestResult):
self._events.append('startTest')
super(LoggingResult, self).startTest(test)
def startTestRun(self):
self._events.append('startTestRun')
super(LoggingResult, self).startTestRun()
def stopTest(self, test):
self._events.append('stopTest')
super(LoggingResult, self).stopTest(test)
def stopTestRun(self):
self._events.append('stopTestRun')
super(LoggingResult, self).stopTestRun()
def addFailure(self, *args):
self._events.append('addFailure')
super(LoggingResult, self).addFailure(*args)
@ -1817,6 +1826,12 @@ class Test_TestResult(TestCase):
self.assertEqual(result.testsRun, 1)
self.assertEqual(result.shouldStop, False)
# "Called before and after tests are run. The default implementation does nothing."
def test_startTestRun_stopTestRun(self):
result = unittest.TestResult()
result.startTestRun()
result.stopTestRun()
# "addSuccess(test)"
# ...
# "Called when the test case test succeeds"
@ -1964,6 +1979,53 @@ class Foo(unittest.TestCase):
class Bar(Foo):
def test2(self): pass
class LoggingTestCase(unittest.TestCase):
"""A test case which logs its calls."""
def __init__(self, events):
super(LoggingTestCase, self).__init__('test')
self.events = events
def setUp(self):
self.events.append('setUp')
def test(self):
self.events.append('test')
def tearDown(self):
self.events.append('tearDown')
class ResultWithNoStartTestRunStopTestRun(object):
"""An object honouring TestResult before startTestRun/stopTestRun."""
def __init__(self):
self.failures = []
self.errors = []
self.testsRun = 0
self.skipped = []
self.expectedFailures = []
self.unexpectedSuccesses = []
self.shouldStop = False
def startTest(self, test):
pass
def stopTest(self, test):
pass
def addError(self, test):
pass
def addFailure(self, test):
pass
def addSuccess(self, test):
pass
def wasSuccessful(self):
return True
################################################################
### /Support code for Test_TestCase
@ -2058,21 +2120,32 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
events = []
result = LoggingResult(events)
class Foo(unittest.TestCase):
class Foo(LoggingTestCase):
def setUp(self):
events.append('setUp')
super(Foo, self).setUp()
raise RuntimeError('raised by Foo.setUp')
def test(self):
events.append('test')
def tearDown(self):
events.append('tearDown')
Foo('test').run(result)
Foo(events).run(result)
expected = ['startTest', 'setUp', 'addError', 'stopTest']
self.assertEqual(events, expected)
# "With a temporary result stopTestRun is called when setUp errors.
def test_run_call_order__error_in_setUp_default_result(self):
events = []
class Foo(LoggingTestCase):
def defaultTestResult(self):
return LoggingResult(self.events)
def setUp(self):
super(Foo, self).setUp()
raise RuntimeError('raised by Foo.setUp')
Foo(events).run()
expected = ['startTestRun', 'startTest', 'setUp', 'addError',
'stopTest', 'stopTestRun']
self.assertEqual(events, expected)
# "When a setUp() method is defined, the test runner will run that method
# prior to each test. Likewise, if a tearDown() method is defined, the
# test runner will invoke that method after each test. In the example,
@ -2084,20 +2157,32 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
events = []
result = LoggingResult(events)
class Foo(unittest.TestCase):
def setUp(self):
events.append('setUp')
class Foo(LoggingTestCase):
def test(self):
events.append('test')
super(Foo, self).test()
raise RuntimeError('raised by Foo.test')
def tearDown(self):
events.append('tearDown')
expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown',
'stopTest']
Foo('test').run(result)
Foo(events).run(result)
self.assertEqual(events, expected)
# "With a default result, an error in the test still results in stopTestRun
# being called."
def test_run_call_order__error_in_test_default_result(self):
events = []
class Foo(LoggingTestCase):
def defaultTestResult(self):
return LoggingResult(self.events)
def test(self):
super(Foo, self).test()
raise RuntimeError('raised by Foo.test')
expected = ['startTestRun', 'startTest', 'setUp', 'test', 'addError',
'tearDown', 'stopTest', 'stopTestRun']
Foo(events).run()
self.assertEqual(events, expected)
# "When a setUp() method is defined, the test runner will run that method
@ -2111,20 +2196,30 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
events = []
result = LoggingResult(events)
class Foo(unittest.TestCase):
def setUp(self):
events.append('setUp')
class Foo(LoggingTestCase):
def test(self):
events.append('test')
super(Foo, self).test()
self.fail('raised by Foo.test')
def tearDown(self):
events.append('tearDown')
expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown',
'stopTest']
Foo('test').run(result)
Foo(events).run(result)
self.assertEqual(events, expected)
# "When a test fails with a default result stopTestRun is still called."
def test_run_call_order__failure_in_test_default_result(self):
class Foo(LoggingTestCase):
def defaultTestResult(self):
return LoggingResult(self.events)
def test(self):
super(Foo, self).test()
self.fail('raised by Foo.test')
expected = ['startTestRun', 'startTest', 'setUp', 'test', 'addFailure',
'tearDown', 'stopTest', 'stopTestRun']
events = []
Foo(events).run()
self.assertEqual(events, expected)
# "When a setUp() method is defined, the test runner will run that method
@ -2138,22 +2233,44 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
events = []
result = LoggingResult(events)
class Foo(unittest.TestCase):
def setUp(self):
events.append('setUp')
def test(self):
events.append('test')
class Foo(LoggingTestCase):
def tearDown(self):
events.append('tearDown')
super(Foo, self).tearDown()
raise RuntimeError('raised by Foo.tearDown')
Foo('test').run(result)
Foo(events).run(result)
expected = ['startTest', 'setUp', 'test', 'tearDown', 'addError',
'stopTest']
self.assertEqual(events, expected)
# "When tearDown errors with a default result stopTestRun is still called."
def test_run_call_order__error_in_tearDown_default_result(self):
class Foo(LoggingTestCase):
def defaultTestResult(self):
return LoggingResult(self.events)
def tearDown(self):
super(Foo, self).tearDown()
raise RuntimeError('raised by Foo.tearDown')
events = []
Foo(events).run()
expected = ['startTestRun', 'startTest', 'setUp', 'test', 'tearDown',
'addError', 'stopTest', 'stopTestRun']
self.assertEqual(events, expected)
# "TestCase.run() still works when the defaultTestResult is a TestResult
# that does not support startTestRun and stopTestRun.
def test_run_call_order_default_result(self):
class Foo(unittest.TestCase):
def defaultTestResult(self):
return ResultWithNoStartTestRunStopTestRun()
def test(self):
pass
Foo('test').run()
# "This class attribute gives the exception raised by the test() method.
# If a test framework needs to use a specialized exception, possibly to
# carry additional information, it must subclass this exception in
@ -2244,7 +2361,9 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
self.failUnless(isinstance(Foo().id(), basestring))
# "If result is omitted or None, a temporary result object is created
# and used, but is not made available to the caller"
# and used, but is not made available to the caller. As TestCase owns the
# temporary result startTestRun and stopTestRun are called.
def test_run__uses_defaultTestResult(self):
events = []
@ -2258,7 +2377,8 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
# Make run() find a result object on its own
Foo('test').run()
expected = ['startTest', 'test', 'addSuccess', 'stopTest']
expected = ['startTestRun', 'startTest', 'test', 'addSuccess',
'stopTest', 'stopTestRun']
self.assertEqual(events, expected)
def testShortDescriptionWithoutDocstring(self):
@ -3215,6 +3335,46 @@ class Test_TestProgram(TestCase):
testLoader=self.FooBarLoader())
class Test_TextTestRunner(TestCase):
"""Tests for TextTestRunner."""
def test_works_with_result_without_startTestRun_stopTestRun(self):
class OldTextResult(ResultWithNoStartTestRunStopTestRun):
separator2 = ''
def printErrors(self):
pass
class Runner(unittest.TextTestRunner):
def __init__(self):
super(Runner, self).__init__(StringIO())
def _makeResult(self):
return OldTextResult()
runner = Runner()
runner.run(unittest.TestSuite())
def test_startTestRun_stopTestRun_called(self):
class LoggingTextResult(LoggingResult):
separator2 = ''
def printErrors(self):
pass
class LoggingRunner(unittest.TextTestRunner):
def __init__(self, events):
super(LoggingRunner, self).__init__(StringIO())
self._events = events
def _makeResult(self):
return LoggingTextResult(self._events)
events = []
runner = LoggingRunner(events)
runner.run(unittest.TestSuite())
expected = ['startTestRun', 'stopTestRun']
self.assertEqual(events, expected)
######################################################################
## Main
######################################################################