Merged revisions 78227,78229,78288,78348,78377,78770,78774-78776,78810 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r78227 | michael.foord | 2010-02-18 14:30:09 -0600 (Thu, 18 Feb 2010) | 1 line unittest.TestCase uses safe_repr for producing failure messages. Partial fix for issue 7956 ........ r78229 | michael.foord | 2010-02-18 15:37:07 -0600 (Thu, 18 Feb 2010) | 1 line Fix unittest.TestCase.assertDictContainsSubset so it can't die with unicode issues when constructing failure messages. Issue 7956 ........ r78288 | michael.foord | 2010-02-21 08:48:59 -0600 (Sun, 21 Feb 2010) | 1 line Silence UnicodeWarning in crazy unittest test. ........ r78348 | michael.foord | 2010-02-22 17:28:32 -0600 (Mon, 22 Feb 2010) | 1 line Support for old TestResult object (unittest) with warnings when using unsupported features. ........ r78377 | michael.foord | 2010-02-23 11:00:53 -0600 (Tue, 23 Feb 2010) | 1 line unittest.TestResult can now be used with the TextTestRunner. TextTestRunner compatible with old TestResult objects. ........ r78770 | michael.foord | 2010-03-07 14:22:12 -0600 (Sun, 07 Mar 2010) | 1 line Fix for potentials errors in constructing unittest failure messages. Plus skipped test methods no longer run setUp and tearDown (Issue 8059) ........ r78774 | michael.foord | 2010-03-07 16:04:55 -0600 (Sun, 07 Mar 2010) | 1 line Addition of setUpClass and setUpModule shared fixtures to unittest. ........ r78775 | michael.foord | 2010-03-07 17:10:36 -0600 (Sun, 07 Mar 2010) | 1 line Fix accidental name rebinding in unittest py3k warning filtering. ........ r78776 | michael.foord | 2010-03-07 17:16:20 -0600 (Sun, 07 Mar 2010) | 1 line Remove accidental print statement from last commit. ........ r78810 | raymond.hettinger | 2010-03-09 02:44:18 -0600 (Tue, 09 Mar 2010) | 5 lines Improve the basic example. * Show both the decorator and regular form for assertRaises() * Use assertTrue() instead of assertIn() to teach useful minimal subset of the API ........
This commit is contained in:
parent
3b8bfeffb3
commit
847a4110ea
@ -177,14 +177,18 @@ Here is a short script to test three functions from the :mod:`random` module::
|
|||||||
self.seq.sort()
|
self.seq.sort()
|
||||||
self.assertEqual(self.seq, list(range(10)))
|
self.assertEqual(self.seq, list(range(10)))
|
||||||
|
|
||||||
|
# should raise an exception for an immutable sequence
|
||||||
|
self.assertRaises(TypeError, random.shuffle, (1,2,3))
|
||||||
|
|
||||||
def test_choice(self):
|
def test_choice(self):
|
||||||
element = random.choice(self.seq)
|
element = random.choice(self.seq)
|
||||||
self.assertIn(element, self.seq)
|
self.assertTrue(element in self.seq)
|
||||||
|
|
||||||
def test_sample(self):
|
def test_sample(self):
|
||||||
self.assertRaises(ValueError, random.sample, self.seq, 20)
|
with self.assertRaises(ValueError):
|
||||||
|
random.sample(self.seq, 20)
|
||||||
for element in random.sample(self.seq, 5):
|
for element in random.sample(self.seq, 5):
|
||||||
self.assertIn(element, self.seq)
|
self.assertTrue(element in self.seq)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -18,10 +18,15 @@ import types
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
import io
|
import io
|
||||||
import pickle
|
import pickle
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
|
||||||
### Support code
|
### Support code
|
||||||
################################################################
|
################################################################
|
||||||
|
|
||||||
|
def resultFactory(*_):
|
||||||
|
return unittest.TestResult()
|
||||||
|
|
||||||
class LoggingResult(unittest.TestResult):
|
class LoggingResult(unittest.TestResult):
|
||||||
def __init__(self, log):
|
def __init__(self, log):
|
||||||
self._events = log
|
self._events = log
|
||||||
@ -2076,6 +2081,70 @@ class Test_TestResult(TestCase):
|
|||||||
'Tests getDescription() for a method with a longer '
|
'Tests getDescription() for a method with a longer '
|
||||||
'docstring.'))
|
'docstring.'))
|
||||||
|
|
||||||
|
classDict = dict(unittest.TestResult.__dict__)
|
||||||
|
for m in ('addSkip', 'addExpectedFailure', 'addUnexpectedSuccess',
|
||||||
|
'__init__'):
|
||||||
|
del classDict[m]
|
||||||
|
|
||||||
|
def __init__(self, stream=None, descriptions=None, verbosity=None):
|
||||||
|
self.failures = []
|
||||||
|
self.errors = []
|
||||||
|
self.testsRun = 0
|
||||||
|
self.shouldStop = False
|
||||||
|
classDict['__init__'] = __init__
|
||||||
|
OldResult = type('OldResult', (object,), classDict)
|
||||||
|
|
||||||
|
class Test_OldTestResult(unittest.TestCase):
|
||||||
|
|
||||||
|
def assertOldResultWarning(self, test, failures):
|
||||||
|
with warnings.catch_warnings(record=True) as log:
|
||||||
|
result = OldResult()
|
||||||
|
test.run(result)
|
||||||
|
self.assertEqual(len(result.failures), failures)
|
||||||
|
warning, = log
|
||||||
|
self.assertIs(warning.category, RuntimeWarning)
|
||||||
|
|
||||||
|
def testOldTestResult(self):
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def testSkip(self):
|
||||||
|
self.skipTest('foobar')
|
||||||
|
@unittest.expectedFailure
|
||||||
|
def testExpectedFail(self):
|
||||||
|
raise TypeError
|
||||||
|
@unittest.expectedFailure
|
||||||
|
def testUnexpectedSuccess(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
for test_name, should_pass in (('testSkip', True),
|
||||||
|
('testExpectedFail', True),
|
||||||
|
('testUnexpectedSuccess', False)):
|
||||||
|
test = Test(test_name)
|
||||||
|
self.assertOldResultWarning(test, int(not should_pass))
|
||||||
|
|
||||||
|
def testOldTestTesultSetup(self):
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.skipTest('no reason')
|
||||||
|
def testFoo(self):
|
||||||
|
pass
|
||||||
|
self.assertOldResultWarning(Test('testFoo'), 0)
|
||||||
|
|
||||||
|
def testOldTestResultClass(self):
|
||||||
|
@unittest.skip('no reason')
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def testFoo(self):
|
||||||
|
pass
|
||||||
|
self.assertOldResultWarning(Test('testFoo'), 0)
|
||||||
|
|
||||||
|
def testOldResultWithRunner(self):
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def testFoo(self):
|
||||||
|
pass
|
||||||
|
runner = unittest.TextTestRunner(resultclass=OldResult,
|
||||||
|
stream=io.StringIO())
|
||||||
|
# This will raise an exception if TextTestRunner can't handle old
|
||||||
|
# test result objects
|
||||||
|
runner.run(Test('testFoo'))
|
||||||
|
|
||||||
### Support code for Test_TestCase
|
### Support code for Test_TestCase
|
||||||
################################################################
|
################################################################
|
||||||
@ -2578,21 +2647,27 @@ class Test_TestCase(TestCase, TestEquality, TestHashing):
|
|||||||
self.assertDictContainsSubset({'a': 1}, {'a': 1, 'b': 2})
|
self.assertDictContainsSubset({'a': 1}, {'a': 1, 'b': 2})
|
||||||
self.assertDictContainsSubset({'a': 1, 'b': 2}, {'a': 1, 'b': 2})
|
self.assertDictContainsSubset({'a': 1, 'b': 2}, {'a': 1, 'b': 2})
|
||||||
|
|
||||||
self.assertRaises(unittest.TestCase.failureException,
|
with self.assertRaises(self.failureException):
|
||||||
self.assertDictContainsSubset, {'a': 2}, {'a': 1},
|
self.assertDictContainsSubset({1: "one"}, {})
|
||||||
'.*Mismatched values:.*')
|
|
||||||
|
|
||||||
self.assertRaises(unittest.TestCase.failureException,
|
with self.assertRaises(self.failureException):
|
||||||
self.assertDictContainsSubset, {'c': 1}, {'a': 1},
|
self.assertDictContainsSubset({'a': 2}, {'a': 1})
|
||||||
'.*Missing:.*')
|
|
||||||
|
|
||||||
self.assertRaises(unittest.TestCase.failureException,
|
with self.assertRaises(self.failureException):
|
||||||
self.assertDictContainsSubset, {'a': 1, 'c': 1},
|
self.assertDictContainsSubset({'c': 1}, {'a': 1})
|
||||||
{'a': 1}, '.*Missing:.*')
|
|
||||||
|
|
||||||
self.assertRaises(unittest.TestCase.failureException,
|
with self.assertRaises(self.failureException):
|
||||||
self.assertDictContainsSubset, {'a': 1, 'c': 1},
|
self.assertDictContainsSubset({'a': 1, 'c': 1}, {'a': 1})
|
||||||
{'a': 1}, '.*Missing:.*Mismatched values:.*')
|
|
||||||
|
with self.assertRaises(self.failureException):
|
||||||
|
self.assertDictContainsSubset({'a': 1, 'c': 1}, {'a': 1})
|
||||||
|
|
||||||
|
with warnings.catch_warnings(record=True):
|
||||||
|
# silence the UnicodeWarning
|
||||||
|
one = ''.join(chr(i) for i in range(255))
|
||||||
|
# this used to cause a UnicodeDecodeError constructing the failure msg
|
||||||
|
with self.assertRaises(self.failureException):
|
||||||
|
self.assertDictContainsSubset({'foo': one}, {'foo': '\uFFFD'})
|
||||||
|
|
||||||
def testAssertEqual(self):
|
def testAssertEqual(self):
|
||||||
equal_pairs = [
|
equal_pairs = [
|
||||||
@ -3028,6 +3103,43 @@ class Test_TestSkipping(TestCase):
|
|||||||
self.assertEqual(result.unexpectedSuccesses, [test])
|
self.assertEqual(result.unexpectedSuccesses, [test])
|
||||||
self.assertTrue(result.wasSuccessful())
|
self.assertTrue(result.wasSuccessful())
|
||||||
|
|
||||||
|
def test_skip_doesnt_run_setup(self):
|
||||||
|
class Foo(unittest.TestCase):
|
||||||
|
wasSetUp = False
|
||||||
|
wasTornDown = False
|
||||||
|
def setUp(self):
|
||||||
|
Foo.wasSetUp = True
|
||||||
|
def tornDown(self):
|
||||||
|
Foo.wasTornDown = True
|
||||||
|
@unittest.skip('testing')
|
||||||
|
def test_1(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
result = unittest.TestResult()
|
||||||
|
test = Foo("test_1")
|
||||||
|
suite = unittest.TestSuite([test])
|
||||||
|
suite.run(result)
|
||||||
|
self.assertEqual(result.skipped, [(test, "testing")])
|
||||||
|
self.assertFalse(Foo.wasSetUp)
|
||||||
|
self.assertFalse(Foo.wasTornDown)
|
||||||
|
|
||||||
|
def test_decorated_skip(self):
|
||||||
|
def decorator(func):
|
||||||
|
def inner(*a):
|
||||||
|
return func(*a)
|
||||||
|
return inner
|
||||||
|
|
||||||
|
class Foo(unittest.TestCase):
|
||||||
|
@decorator
|
||||||
|
@unittest.skip('testing')
|
||||||
|
def test_1(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
result = unittest.TestResult()
|
||||||
|
test = Foo("test_1")
|
||||||
|
suite = unittest.TestSuite([test])
|
||||||
|
suite.run(result)
|
||||||
|
self.assertEqual(result.skipped, [(test, "testing")])
|
||||||
|
|
||||||
|
|
||||||
class Test_Assertions(TestCase):
|
class Test_Assertions(TestCase):
|
||||||
@ -3131,6 +3243,16 @@ class TestLongMessage(TestCase):
|
|||||||
self.assertEquals(self.testableTrue._formatMessage(None, "foo"), "foo")
|
self.assertEquals(self.testableTrue._formatMessage(None, "foo"), "foo")
|
||||||
self.assertEquals(self.testableTrue._formatMessage("foo", "bar"), "bar : foo")
|
self.assertEquals(self.testableTrue._formatMessage("foo", "bar"), "bar : foo")
|
||||||
|
|
||||||
|
# This blows up if _formatMessage uses string concatenation
|
||||||
|
self.testableTrue._formatMessage(object(), 'foo')
|
||||||
|
|
||||||
|
def test_formatMessage_unicode_error(self):
|
||||||
|
with warnings.catch_warnings(record=True):
|
||||||
|
# This causes a UnicodeWarning due to its craziness
|
||||||
|
one = ''.join(chr(i) for i in range(255))
|
||||||
|
# this used to cause a UnicodeDecodeError constructing msg
|
||||||
|
self.testableTrue._formatMessage(one, '\uFFFD')
|
||||||
|
|
||||||
def assertMessages(self, methodName, args, errors):
|
def assertMessages(self, methodName, args, errors):
|
||||||
def getMethod(i):
|
def getMethod(i):
|
||||||
useTestableFalse = i < 2
|
useTestableFalse = i < 2
|
||||||
@ -3795,6 +3917,397 @@ class TestDiscovery(TestCase):
|
|||||||
self.assertEqual(program.verbosity, 2)
|
self.assertEqual(program.verbosity, 2)
|
||||||
|
|
||||||
|
|
||||||
|
class TestSetups(unittest.TestCase):
|
||||||
|
|
||||||
|
def getRunner(self):
|
||||||
|
return unittest.TextTestRunner(resultclass=resultFactory,
|
||||||
|
stream=io.StringIO())
|
||||||
|
def runTests(self, *cases):
|
||||||
|
suite = unittest.TestSuite()
|
||||||
|
for case in cases:
|
||||||
|
tests = unittest.defaultTestLoader.loadTestsFromTestCase(case)
|
||||||
|
suite.addTests(tests)
|
||||||
|
|
||||||
|
runner = self.getRunner()
|
||||||
|
|
||||||
|
# creating a nested suite exposes some potential bugs
|
||||||
|
realSuite = unittest.TestSuite()
|
||||||
|
realSuite.addTest(suite)
|
||||||
|
# adding empty suites to the end exposes potential bugs
|
||||||
|
suite.addTest(unittest.TestSuite())
|
||||||
|
realSuite.addTest(unittest.TestSuite())
|
||||||
|
return runner.run(realSuite)
|
||||||
|
|
||||||
|
def test_setup_class(self):
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
setUpCalled = 0
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
Test.setUpCalled += 1
|
||||||
|
unittest.TestCase.setUpClass()
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
result = self.runTests(Test)
|
||||||
|
|
||||||
|
self.assertEqual(Test.setUpCalled, 1)
|
||||||
|
self.assertEqual(result.testsRun, 2)
|
||||||
|
self.assertEqual(len(result.errors), 0)
|
||||||
|
|
||||||
|
def test_teardown_class(self):
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
tearDownCalled = 0
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
Test.tearDownCalled += 1
|
||||||
|
unittest.TestCase.tearDownClass()
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
result = self.runTests(Test)
|
||||||
|
|
||||||
|
self.assertEqual(Test.tearDownCalled, 1)
|
||||||
|
self.assertEqual(result.testsRun, 2)
|
||||||
|
self.assertEqual(len(result.errors), 0)
|
||||||
|
|
||||||
|
def test_teardown_class_two_classes(self):
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
tearDownCalled = 0
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
Test.tearDownCalled += 1
|
||||||
|
unittest.TestCase.tearDownClass()
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Test2(unittest.TestCase):
|
||||||
|
tearDownCalled = 0
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
Test2.tearDownCalled += 1
|
||||||
|
unittest.TestCase.tearDownClass()
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
result = self.runTests(Test, Test2)
|
||||||
|
|
||||||
|
self.assertEqual(Test.tearDownCalled, 1)
|
||||||
|
self.assertEqual(Test2.tearDownCalled, 1)
|
||||||
|
self.assertEqual(result.testsRun, 4)
|
||||||
|
self.assertEqual(len(result.errors), 0)
|
||||||
|
|
||||||
|
def test_error_in_setupclass(self):
|
||||||
|
class BrokenTest(unittest.TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
raise TypeError('foo')
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
result = self.runTests(BrokenTest)
|
||||||
|
|
||||||
|
self.assertEqual(result.testsRun, 0)
|
||||||
|
self.assertEqual(len(result.errors), 1)
|
||||||
|
error, _ = result.errors[0]
|
||||||
|
self.assertEqual(str(error),
|
||||||
|
'classSetUp (%s.BrokenTest)' % __name__)
|
||||||
|
|
||||||
|
def test_error_in_teardown_class(self):
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
tornDown = 0
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
Test.tornDown += 1
|
||||||
|
raise TypeError('foo')
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Test2(unittest.TestCase):
|
||||||
|
tornDown = 0
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
Test2.tornDown += 1
|
||||||
|
raise TypeError('foo')
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
result = self.runTests(Test, Test2)
|
||||||
|
self.assertEqual(result.testsRun, 4)
|
||||||
|
self.assertEqual(len(result.errors), 2)
|
||||||
|
self.assertEqual(Test.tornDown, 1)
|
||||||
|
self.assertEqual(Test2.tornDown, 1)
|
||||||
|
|
||||||
|
error, _ = result.errors[0]
|
||||||
|
self.assertEqual(str(error),
|
||||||
|
'classTearDown (%s.Test)' % __name__)
|
||||||
|
|
||||||
|
def test_class_not_torndown_when_setup_fails(self):
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
tornDown = False
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
raise TypeError
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
Test.tornDown = True
|
||||||
|
raise TypeError('foo')
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.runTests(Test)
|
||||||
|
self.assertFalse(Test.tornDown)
|
||||||
|
|
||||||
|
def test_class_not_setup_or_torndown_when_skipped(self):
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
classSetUp = False
|
||||||
|
tornDown = False
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
Test.classSetUp = True
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
Test.tornDown = True
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
Test = unittest.skip("hop")(Test)
|
||||||
|
self.runTests(Test)
|
||||||
|
self.assertFalse(Test.classSetUp)
|
||||||
|
self.assertFalse(Test.tornDown)
|
||||||
|
|
||||||
|
def test_setup_teardown_order_with_pathological_suite(self):
|
||||||
|
results = []
|
||||||
|
|
||||||
|
class Module1(object):
|
||||||
|
@staticmethod
|
||||||
|
def setUpModule():
|
||||||
|
results.append('Module1.setUpModule')
|
||||||
|
@staticmethod
|
||||||
|
def tearDownModule():
|
||||||
|
results.append('Module1.tearDownModule')
|
||||||
|
|
||||||
|
class Module2(object):
|
||||||
|
@staticmethod
|
||||||
|
def setUpModule():
|
||||||
|
results.append('Module2.setUpModule')
|
||||||
|
@staticmethod
|
||||||
|
def tearDownModule():
|
||||||
|
results.append('Module2.tearDownModule')
|
||||||
|
|
||||||
|
class Test1(unittest.TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
results.append('setup 1')
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
results.append('teardown 1')
|
||||||
|
def testOne(self):
|
||||||
|
results.append('Test1.testOne')
|
||||||
|
def testTwo(self):
|
||||||
|
results.append('Test1.testTwo')
|
||||||
|
|
||||||
|
class Test2(unittest.TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
results.append('setup 2')
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
results.append('teardown 2')
|
||||||
|
def testOne(self):
|
||||||
|
results.append('Test2.testOne')
|
||||||
|
def testTwo(self):
|
||||||
|
results.append('Test2.testTwo')
|
||||||
|
|
||||||
|
class Test3(unittest.TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
results.append('setup 3')
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
results.append('teardown 3')
|
||||||
|
def testOne(self):
|
||||||
|
results.append('Test3.testOne')
|
||||||
|
def testTwo(self):
|
||||||
|
results.append('Test3.testTwo')
|
||||||
|
|
||||||
|
Test1.__module__ = Test2.__module__ = 'Module'
|
||||||
|
Test3.__module__ = 'Module2'
|
||||||
|
sys.modules['Module'] = Module1
|
||||||
|
sys.modules['Module2'] = Module2
|
||||||
|
|
||||||
|
first = unittest.TestSuite((Test1('testOne'),))
|
||||||
|
second = unittest.TestSuite((Test1('testTwo'),))
|
||||||
|
third = unittest.TestSuite((Test2('testOne'),))
|
||||||
|
fourth = unittest.TestSuite((Test2('testTwo'),))
|
||||||
|
fifth = unittest.TestSuite((Test3('testOne'),))
|
||||||
|
sixth = unittest.TestSuite((Test3('testTwo'),))
|
||||||
|
suite = unittest.TestSuite((first, second, third, fourth, fifth, sixth))
|
||||||
|
|
||||||
|
runner = self.getRunner()
|
||||||
|
result = runner.run(suite)
|
||||||
|
self.assertEqual(result.testsRun, 6)
|
||||||
|
self.assertEqual(len(result.errors), 0)
|
||||||
|
|
||||||
|
self.assertEqual(results,
|
||||||
|
['Module1.setUpModule', 'setup 1',
|
||||||
|
'Test1.testOne', 'Test1.testTwo', 'teardown 1',
|
||||||
|
'setup 2', 'Test2.testOne', 'Test2.testTwo',
|
||||||
|
'teardown 2', 'Module1.tearDownModule',
|
||||||
|
'Module2.setUpModule', 'setup 3',
|
||||||
|
'Test3.testOne', 'Test3.testTwo',
|
||||||
|
'teardown 3', 'Module2.tearDownModule'])
|
||||||
|
|
||||||
|
def test_setup_module(self):
|
||||||
|
class Module(object):
|
||||||
|
moduleSetup = 0
|
||||||
|
@staticmethod
|
||||||
|
def setUpModule():
|
||||||
|
Module.moduleSetup += 1
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
Test.__module__ = 'Module'
|
||||||
|
sys.modules['Module'] = Module
|
||||||
|
|
||||||
|
result = self.runTests(Test)
|
||||||
|
self.assertEqual(Module.moduleSetup, 1)
|
||||||
|
self.assertEqual(result.testsRun, 2)
|
||||||
|
self.assertEqual(len(result.errors), 0)
|
||||||
|
|
||||||
|
def test_error_in_setup_module(self):
|
||||||
|
class Module(object):
|
||||||
|
moduleSetup = 0
|
||||||
|
moduleTornDown = 0
|
||||||
|
@staticmethod
|
||||||
|
def setUpModule():
|
||||||
|
Module.moduleSetup += 1
|
||||||
|
raise TypeError('foo')
|
||||||
|
@staticmethod
|
||||||
|
def tearDownModule():
|
||||||
|
Module.moduleTornDown += 1
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
classSetUp = False
|
||||||
|
classTornDown = False
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
Test.classSetUp = True
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
Test.classTornDown = True
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Test2(unittest.TestCase):
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
Test.__module__ = 'Module'
|
||||||
|
Test2.__module__ = 'Module'
|
||||||
|
sys.modules['Module'] = Module
|
||||||
|
|
||||||
|
result = self.runTests(Test, Test2)
|
||||||
|
self.assertEqual(Module.moduleSetup, 1)
|
||||||
|
self.assertEqual(Module.moduleTornDown, 0)
|
||||||
|
self.assertEqual(result.testsRun, 0)
|
||||||
|
self.assertFalse(Test.classSetUp)
|
||||||
|
self.assertFalse(Test.classTornDown)
|
||||||
|
self.assertEqual(len(result.errors), 1)
|
||||||
|
error, _ = result.errors[0]
|
||||||
|
self.assertEqual(str(error), 'setUpModule (Module)')
|
||||||
|
|
||||||
|
def test_testcase_with_missing_module(self):
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
Test.__module__ = 'Module'
|
||||||
|
sys.modules.pop('Module', None)
|
||||||
|
|
||||||
|
result = self.runTests(Test)
|
||||||
|
self.assertEqual(result.testsRun, 2)
|
||||||
|
|
||||||
|
def test_teardown_module(self):
|
||||||
|
class Module(object):
|
||||||
|
moduleTornDown = 0
|
||||||
|
@staticmethod
|
||||||
|
def tearDownModule():
|
||||||
|
Module.moduleTornDown += 1
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
Test.__module__ = 'Module'
|
||||||
|
sys.modules['Module'] = Module
|
||||||
|
|
||||||
|
result = self.runTests(Test)
|
||||||
|
self.assertEqual(Module.moduleTornDown, 1)
|
||||||
|
self.assertEqual(result.testsRun, 2)
|
||||||
|
self.assertEqual(len(result.errors), 0)
|
||||||
|
|
||||||
|
def test_error_in_teardown_module(self):
|
||||||
|
class Module(object):
|
||||||
|
moduleTornDown = 0
|
||||||
|
@staticmethod
|
||||||
|
def tearDownModule():
|
||||||
|
Module.moduleTornDown += 1
|
||||||
|
raise TypeError('foo')
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
classSetUp = False
|
||||||
|
classTornDown = False
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
Test.classSetUp = True
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
Test.classTornDown = True
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Test2(unittest.TestCase):
|
||||||
|
def test_one(self):
|
||||||
|
pass
|
||||||
|
def test_two(self):
|
||||||
|
pass
|
||||||
|
Test.__module__ = 'Module'
|
||||||
|
Test2.__module__ = 'Module'
|
||||||
|
sys.modules['Module'] = Module
|
||||||
|
|
||||||
|
result = self.runTests(Test, Test2)
|
||||||
|
self.assertEqual(Module.moduleTornDown, 1)
|
||||||
|
self.assertEqual(result.testsRun, 4)
|
||||||
|
self.assertTrue(Test.classSetUp)
|
||||||
|
self.assertTrue(Test.classTornDown)
|
||||||
|
self.assertEqual(len(result.errors), 1)
|
||||||
|
error, _ = result.errors[0]
|
||||||
|
self.assertEqual(str(error), 'tearDownModule (Module)')
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
## Main
|
## Main
|
||||||
######################################################################
|
######################################################################
|
||||||
@ -3803,7 +4316,8 @@ def test_main():
|
|||||||
support.run_unittest(Test_TestCase, Test_TestLoader,
|
support.run_unittest(Test_TestCase, Test_TestLoader,
|
||||||
Test_TestSuite, Test_TestResult, Test_FunctionTestCase,
|
Test_TestSuite, Test_TestResult, Test_FunctionTestCase,
|
||||||
Test_TestSkipping, Test_Assertions, TestLongMessage,
|
Test_TestSkipping, Test_Assertions, TestLongMessage,
|
||||||
Test_TestProgram, TestCleanUp, TestDiscovery, Test_TextTestRunner)
|
Test_TestProgram, TestCleanUp, TestDiscovery, Test_TextTestRunner,
|
||||||
|
Test_OldTestResult, TestSetups)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_main()
|
test_main()
|
||||||
|
@ -51,13 +51,12 @@ __all__ = ['TestResult', 'TestCase', 'TestSuite',
|
|||||||
|
|
||||||
# Expose obsolete functions for backwards compatibility
|
# Expose obsolete functions for backwards compatibility
|
||||||
__all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases'])
|
__all__.extend(['getTestCaseNames', 'makeSuite', 'findTestCases'])
|
||||||
__all__.append('_TextTestResult')
|
|
||||||
|
|
||||||
|
|
||||||
from .result import TestResult
|
from .result import TestResult
|
||||||
from .case import (TestCase, FunctionTestCase, SkipTest, skip, skipIf,
|
from .case import (TestCase, FunctionTestCase, SkipTest, skip, skipIf,
|
||||||
skipUnless, expectedFailure)
|
skipUnless, expectedFailure)
|
||||||
from .suite import TestSuite
|
from .suite import BaseTestSuite, TestSuite
|
||||||
from .loader import (TestLoader, defaultTestLoader, makeSuite, getTestCaseNames,
|
from .loader import (TestLoader, defaultTestLoader, makeSuite, getTestCaseNames,
|
||||||
findTestCases)
|
findTestCases)
|
||||||
from .main import TestProgram, main
|
from .main import TestProgram, main
|
||||||
|
@ -7,7 +7,9 @@ import pprint
|
|||||||
import re
|
import re
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from . import result, util
|
from . import result
|
||||||
|
from .util import (strclass, safe_repr, sorted_list_difference,
|
||||||
|
unorderable_list_difference)
|
||||||
|
|
||||||
|
|
||||||
class SkipTest(Exception):
|
class SkipTest(Exception):
|
||||||
@ -44,14 +46,15 @@ def skip(reason):
|
|||||||
Unconditionally skip a test.
|
Unconditionally skip a test.
|
||||||
"""
|
"""
|
||||||
def decorator(test_item):
|
def decorator(test_item):
|
||||||
if isinstance(test_item, type) and issubclass(test_item, TestCase):
|
if not (isinstance(test_item, type) and issubclass(test_item, TestCase)):
|
||||||
test_item.__unittest_skip__ = True
|
@functools.wraps(test_item)
|
||||||
test_item.__unittest_skip_why__ = reason
|
def skip_wrapper(*args, **kwargs):
|
||||||
return test_item
|
raise SkipTest(reason)
|
||||||
@functools.wraps(test_item)
|
test_item = skip_wrapper
|
||||||
def skip_wrapper(*args, **kwargs):
|
|
||||||
raise SkipTest(reason)
|
test_item.__unittest_skip__ = True
|
||||||
return skip_wrapper
|
test_item.__unittest_skip_why__ = reason
|
||||||
|
return test_item
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
def skipIf(condition, reason):
|
def skipIf(condition, reason):
|
||||||
@ -164,6 +167,9 @@ class TestCase(object):
|
|||||||
|
|
||||||
longMessage = False
|
longMessage = False
|
||||||
|
|
||||||
|
# Attribute used by TestSuite for classSetUp
|
||||||
|
|
||||||
|
_classSetupFailed = False
|
||||||
|
|
||||||
def __init__(self, methodName='runTest'):
|
def __init__(self, methodName='runTest'):
|
||||||
"""Create an instance of the class that will use the named test
|
"""Create an instance of the class that will use the named test
|
||||||
@ -175,7 +181,7 @@ class TestCase(object):
|
|||||||
try:
|
try:
|
||||||
testMethod = getattr(self, methodName)
|
testMethod = getattr(self, methodName)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise ValueError("no such test method in %s: %s" % \
|
raise ValueError("no such test method in %s: %s" %
|
||||||
(self.__class__, methodName))
|
(self.__class__, methodName))
|
||||||
self._testMethodDoc = testMethod.__doc__
|
self._testMethodDoc = testMethod.__doc__
|
||||||
self._cleanups = []
|
self._cleanups = []
|
||||||
@ -222,6 +228,14 @@ class TestCase(object):
|
|||||||
"Hook method for deconstructing the test fixture after testing it."
|
"Hook method for deconstructing the test fixture after testing it."
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
"Hook method for setting up class fixture before running tests in the class."
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
"Hook method for deconstructing the class fixture after running all tests in the class."
|
||||||
|
|
||||||
def countTestCases(self):
|
def countTestCases(self):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@ -240,7 +254,7 @@ class TestCase(object):
|
|||||||
|
|
||||||
|
|
||||||
def id(self):
|
def id(self):
|
||||||
return "%s.%s" % (util.strclass(self.__class__), self._testMethodName)
|
return "%s.%s" % (strclass(self.__class__), self._testMethodName)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if type(self) is not type(other):
|
if type(self) is not type(other):
|
||||||
@ -255,11 +269,20 @@ class TestCase(object):
|
|||||||
return hash((type(self), self._testMethodName))
|
return hash((type(self), self._testMethodName))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s (%s)" % (self._testMethodName, util.strclass(self.__class__))
|
return "%s (%s)" % (self._testMethodName, strclass(self.__class__))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s testMethod=%s>" % \
|
return "<%s testMethod=%s>" % \
|
||||||
(util.strclass(self.__class__), self._testMethodName)
|
(strclass(self.__class__), self._testMethodName)
|
||||||
|
|
||||||
|
def _addSkip(self, result, reason):
|
||||||
|
addSkip = getattr(result, 'addSkip', None)
|
||||||
|
if addSkip is not None:
|
||||||
|
addSkip(self, reason)
|
||||||
|
else:
|
||||||
|
warnings.warn("TestResult has no addSkip method, skips not reported",
|
||||||
|
RuntimeWarning, 2)
|
||||||
|
result.addSuccess(self)
|
||||||
|
|
||||||
def run(self, result=None):
|
def run(self, result=None):
|
||||||
orig_result = result
|
orig_result = result
|
||||||
@ -271,20 +294,24 @@ class TestCase(object):
|
|||||||
|
|
||||||
self._resultForDoCleanups = result
|
self._resultForDoCleanups = result
|
||||||
result.startTest(self)
|
result.startTest(self)
|
||||||
if getattr(self.__class__, "__unittest_skip__", False):
|
|
||||||
# If the whole class was skipped.
|
testMethod = getattr(self, self._testMethodName)
|
||||||
|
if (getattr(self.__class__, "__unittest_skip__", False) or
|
||||||
|
getattr(testMethod, "__unittest_skip__", False)):
|
||||||
|
# If the class or method was skipped.
|
||||||
try:
|
try:
|
||||||
result.addSkip(self, self.__class__.__unittest_skip_why__)
|
skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
|
||||||
|
or getattr(testMethod, '__unittest_skip_why__', ''))
|
||||||
|
self._addSkip(result, skip_why)
|
||||||
finally:
|
finally:
|
||||||
result.stopTest(self)
|
result.stopTest(self)
|
||||||
return
|
return
|
||||||
testMethod = getattr(self, self._testMethodName)
|
|
||||||
try:
|
try:
|
||||||
success = False
|
success = False
|
||||||
try:
|
try:
|
||||||
self.setUp()
|
self.setUp()
|
||||||
except SkipTest as e:
|
except SkipTest as e:
|
||||||
result.addSkip(self, str(e))
|
self._addSkip(result, str(e))
|
||||||
except Exception:
|
except Exception:
|
||||||
result.addError(self, sys.exc_info())
|
result.addError(self, sys.exc_info())
|
||||||
else:
|
else:
|
||||||
@ -293,11 +320,23 @@ class TestCase(object):
|
|||||||
except self.failureException:
|
except self.failureException:
|
||||||
result.addFailure(self, sys.exc_info())
|
result.addFailure(self, sys.exc_info())
|
||||||
except _ExpectedFailure as e:
|
except _ExpectedFailure as e:
|
||||||
result.addExpectedFailure(self, e.exc_info)
|
addExpectedFailure = getattr(result, 'addExpectedFailure', None)
|
||||||
|
if addExpectedFailure is not None:
|
||||||
|
addExpectedFailure(self, e.exc_info)
|
||||||
|
else:
|
||||||
|
warnings.warn("TestResult has no addExpectedFailure method, reporting as passes",
|
||||||
|
RuntimeWarning)
|
||||||
|
result.addSuccess(self)
|
||||||
except _UnexpectedSuccess:
|
except _UnexpectedSuccess:
|
||||||
result.addUnexpectedSuccess(self)
|
addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None)
|
||||||
|
if addUnexpectedSuccess is not None:
|
||||||
|
addUnexpectedSuccess(self)
|
||||||
|
else:
|
||||||
|
warnings.warn("TestResult has no addUnexpectedSuccess method, reporting as failures",
|
||||||
|
RuntimeWarning)
|
||||||
|
result.addFailure(self, sys.exc_info())
|
||||||
except SkipTest as e:
|
except SkipTest as e:
|
||||||
result.addSkip(self, str(e))
|
self._addSkip(result, str(e))
|
||||||
except Exception:
|
except Exception:
|
||||||
result.addError(self, sys.exc_info())
|
result.addError(self, sys.exc_info())
|
||||||
else:
|
else:
|
||||||
@ -354,13 +393,13 @@ class TestCase(object):
|
|||||||
def assertFalse(self, expr, msg=None):
|
def assertFalse(self, expr, msg=None):
|
||||||
"Fail the test if the expression is true."
|
"Fail the test if the expression is true."
|
||||||
if expr:
|
if expr:
|
||||||
msg = self._formatMessage(msg, "%r is not False" % expr)
|
msg = self._formatMessage(msg, "%s is not False" % safe_repr(expr))
|
||||||
raise self.failureException(msg)
|
raise self.failureException(msg)
|
||||||
|
|
||||||
def assertTrue(self, expr, msg=None):
|
def assertTrue(self, expr, msg=None):
|
||||||
"""Fail the test unless the expression is true."""
|
"""Fail the test unless the expression is true."""
|
||||||
if not expr:
|
if not expr:
|
||||||
msg = self._formatMessage(msg, "%r is not True" % expr)
|
msg = self._formatMessage(msg, "%s is not True" % safe_repr(expr))
|
||||||
raise self.failureException(msg)
|
raise self.failureException(msg)
|
||||||
|
|
||||||
def _formatMessage(self, msg, standardMsg):
|
def _formatMessage(self, msg, standardMsg):
|
||||||
@ -377,7 +416,12 @@ class TestCase(object):
|
|||||||
return msg or standardMsg
|
return msg or standardMsg
|
||||||
if msg is None:
|
if msg is None:
|
||||||
return standardMsg
|
return standardMsg
|
||||||
return standardMsg + ' : ' + msg
|
try:
|
||||||
|
# don't switch to '{}' formatting in Python 2.X
|
||||||
|
# it changes the way unicode input is handled
|
||||||
|
return '%s : %s' % (standardMsg, msg)
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
return '%s : %s' % (safe_repr(standardMsg), safe_repr(msg))
|
||||||
|
|
||||||
|
|
||||||
def assertRaises(self, excClass, callableObj=None, *args, **kwargs):
|
def assertRaises(self, excClass, callableObj=None, *args, **kwargs):
|
||||||
@ -436,7 +480,7 @@ class TestCase(object):
|
|||||||
def _baseAssertEqual(self, first, second, msg=None):
|
def _baseAssertEqual(self, first, second, msg=None):
|
||||||
"""The default assertEqual implementation, not type specific."""
|
"""The default assertEqual implementation, not type specific."""
|
||||||
if not first == second:
|
if not first == second:
|
||||||
standardMsg = '%r != %r' % (first, second)
|
standardMsg = '%s != %s' % (safe_repr(first), safe_repr(second))
|
||||||
msg = self._formatMessage(msg, standardMsg)
|
msg = self._formatMessage(msg, standardMsg)
|
||||||
raise self.failureException(msg)
|
raise self.failureException(msg)
|
||||||
|
|
||||||
@ -452,7 +496,8 @@ class TestCase(object):
|
|||||||
operator.
|
operator.
|
||||||
"""
|
"""
|
||||||
if not first != second:
|
if not first != second:
|
||||||
msg = self._formatMessage(msg, '%r == %r' % (first, second))
|
msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first),
|
||||||
|
safe_repr(second)))
|
||||||
raise self.failureException(msg)
|
raise self.failureException(msg)
|
||||||
|
|
||||||
def assertAlmostEqual(self, first, second, *, places=7, msg=None):
|
def assertAlmostEqual(self, first, second, *, places=7, msg=None):
|
||||||
@ -467,10 +512,12 @@ class TestCase(object):
|
|||||||
compare almost equal.
|
compare almost equal.
|
||||||
"""
|
"""
|
||||||
if first == second:
|
if first == second:
|
||||||
# shortcut for ite
|
# shortcut for inf
|
||||||
return
|
return
|
||||||
if round(abs(second-first), places) != 0:
|
if round(abs(second-first), places) != 0:
|
||||||
standardMsg = '%r != %r within %r places' % (first, second, places)
|
standardMsg = '%s != %s within %r places' % (safe_repr(first),
|
||||||
|
safe_repr(second),
|
||||||
|
places)
|
||||||
msg = self._formatMessage(msg, standardMsg)
|
msg = self._formatMessage(msg, standardMsg)
|
||||||
raise self.failureException(msg)
|
raise self.failureException(msg)
|
||||||
|
|
||||||
@ -485,7 +532,9 @@ class TestCase(object):
|
|||||||
Objects that are equal automatically fail.
|
Objects that are equal automatically fail.
|
||||||
"""
|
"""
|
||||||
if (first == second) or round(abs(second-first), places) == 0:
|
if (first == second) or round(abs(second-first), places) == 0:
|
||||||
standardMsg = '%r == %r within %r places' % (first, second, places)
|
standardMsg = '%s == %s within %r places' % (safe_repr(first),
|
||||||
|
safe_repr(second),
|
||||||
|
places)
|
||||||
msg = self._formatMessage(msg, standardMsg)
|
msg = self._formatMessage(msg, standardMsg)
|
||||||
raise self.failureException(msg)
|
raise self.failureException(msg)
|
||||||
|
|
||||||
@ -535,11 +584,11 @@ class TestCase(object):
|
|||||||
if seq_type != None:
|
if seq_type != None:
|
||||||
seq_type_name = seq_type.__name__
|
seq_type_name = seq_type.__name__
|
||||||
if not isinstance(seq1, seq_type):
|
if not isinstance(seq1, seq_type):
|
||||||
raise self.failureException('First sequence is not a %s: %r'
|
raise self.failureException('First sequence is not a %s: %s'
|
||||||
% (seq_type_name, seq1))
|
% (seq_type_name, safe_repr(seq1)))
|
||||||
if not isinstance(seq2, seq_type):
|
if not isinstance(seq2, seq_type):
|
||||||
raise self.failureException('Second sequence is not a %s: %r'
|
raise self.failureException('Second sequence is not a %s: %s'
|
||||||
% (seq_type_name, seq2))
|
% (seq_type_name, safe_repr(seq2)))
|
||||||
else:
|
else:
|
||||||
seq_type_name = "sequence"
|
seq_type_name = "sequence"
|
||||||
|
|
||||||
@ -561,8 +610,8 @@ class TestCase(object):
|
|||||||
if seq1 == seq2:
|
if seq1 == seq2:
|
||||||
return
|
return
|
||||||
|
|
||||||
seq1_repr = repr(seq1)
|
seq1_repr = safe_repr(seq1)
|
||||||
seq2_repr = repr(seq2)
|
seq2_repr = safe_repr(seq2)
|
||||||
if len(seq1_repr) > 30:
|
if len(seq1_repr) > 30:
|
||||||
seq1_repr = seq1_repr[:30] + '...'
|
seq1_repr = seq1_repr[:30] + '...'
|
||||||
if len(seq2_repr) > 30:
|
if len(seq2_repr) > 30:
|
||||||
@ -689,25 +738,28 @@ class TestCase(object):
|
|||||||
def assertIn(self, member, container, msg=None):
|
def assertIn(self, member, container, msg=None):
|
||||||
"""Just like self.assertTrue(a in b), but with a nicer default message."""
|
"""Just like self.assertTrue(a in b), but with a nicer default message."""
|
||||||
if member not in container:
|
if member not in container:
|
||||||
standardMsg = '%r not found in %r' % (member, container)
|
standardMsg = '%s not found in %s' % (safe_repr(member),
|
||||||
|
safe_repr(container))
|
||||||
self.fail(self._formatMessage(msg, standardMsg))
|
self.fail(self._formatMessage(msg, standardMsg))
|
||||||
|
|
||||||
def assertNotIn(self, member, container, msg=None):
|
def assertNotIn(self, member, container, msg=None):
|
||||||
"""Just like self.assertTrue(a not in b), but with a nicer default message."""
|
"""Just like self.assertTrue(a not in b), but with a nicer default message."""
|
||||||
if member in container:
|
if member in container:
|
||||||
standardMsg = '%r unexpectedly found in %r' % (member, container)
|
standardMsg = '%s unexpectedly found in %s' % (safe_repr(member),
|
||||||
|
safe_repr(container))
|
||||||
self.fail(self._formatMessage(msg, standardMsg))
|
self.fail(self._formatMessage(msg, standardMsg))
|
||||||
|
|
||||||
def assertIs(self, expr1, expr2, msg=None):
|
def assertIs(self, expr1, expr2, msg=None):
|
||||||
"""Just like self.assertTrue(a is b), but with a nicer default message."""
|
"""Just like self.assertTrue(a is b), but with a nicer default message."""
|
||||||
if expr1 is not expr2:
|
if expr1 is not expr2:
|
||||||
standardMsg = '%r is not %r' % (expr1, expr2)
|
standardMsg = '%s is not %s' % (safe_repr(expr1),
|
||||||
|
safe_repr(expr2))
|
||||||
self.fail(self._formatMessage(msg, standardMsg))
|
self.fail(self._formatMessage(msg, standardMsg))
|
||||||
|
|
||||||
def assertIsNot(self, expr1, expr2, msg=None):
|
def assertIsNot(self, expr1, expr2, msg=None):
|
||||||
"""Just like self.assertTrue(a is not b), but with a nicer default message."""
|
"""Just like self.assertTrue(a is not b), but with a nicer default message."""
|
||||||
if expr1 is expr2:
|
if expr1 is expr2:
|
||||||
standardMsg = 'unexpectedly identical: %r' % (expr1,)
|
standardMsg = 'unexpectedly identical: %s' % (safe_repr(expr1),)
|
||||||
self.fail(self._formatMessage(msg, standardMsg))
|
self.fail(self._formatMessage(msg, standardMsg))
|
||||||
|
|
||||||
def assertDictEqual(self, d1, d2, msg=None):
|
def assertDictEqual(self, d1, d2, msg=None):
|
||||||
@ -729,14 +781,16 @@ class TestCase(object):
|
|||||||
missing.append(key)
|
missing.append(key)
|
||||||
elif value != actual[key]:
|
elif value != actual[key]:
|
||||||
mismatched.append('%s, expected: %s, actual: %s' %
|
mismatched.append('%s, expected: %s, actual: %s' %
|
||||||
(key, value, actual[key]))
|
(safe_repr(key), safe_repr(value),
|
||||||
|
safe_repr(actual[key])))
|
||||||
|
|
||||||
if not (missing or mismatched):
|
if not (missing or mismatched):
|
||||||
return
|
return
|
||||||
|
|
||||||
standardMsg = ''
|
standardMsg = ''
|
||||||
if missing:
|
if missing:
|
||||||
standardMsg = 'Missing: %r' % ','.join(missing)
|
standardMsg = 'Missing: %s' % ','.join(safe_repr(m) for m in
|
||||||
|
missing)
|
||||||
if mismatched:
|
if mismatched:
|
||||||
if standardMsg:
|
if standardMsg:
|
||||||
standardMsg += '; '
|
standardMsg += '; '
|
||||||
@ -758,10 +812,8 @@ class TestCase(object):
|
|||||||
try:
|
try:
|
||||||
expected = set(expected_seq)
|
expected = set(expected_seq)
|
||||||
actual = set(actual_seq)
|
actual = set(actual_seq)
|
||||||
missing = list(expected.difference(actual))
|
missing = sorted(expected.difference(actual))
|
||||||
unexpected = list(actual.difference(expected))
|
unexpected = sorted(actual.difference(expected))
|
||||||
missing.sort()
|
|
||||||
unexpected.sort()
|
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# Fall back to slower list-compare if any of the objects are
|
# Fall back to slower list-compare if any of the objects are
|
||||||
# not hashable.
|
# not hashable.
|
||||||
@ -771,16 +823,17 @@ class TestCase(object):
|
|||||||
expected.sort()
|
expected.sort()
|
||||||
actual.sort()
|
actual.sort()
|
||||||
except TypeError:
|
except TypeError:
|
||||||
missing, unexpected = util.unorderable_list_difference(expected,
|
missing, unexpected = unorderable_list_difference(expected,
|
||||||
actual)
|
|
||||||
else:
|
|
||||||
missing, unexpected = util.sorted_list_difference(expected,
|
|
||||||
actual)
|
actual)
|
||||||
|
else:
|
||||||
|
missing, unexpected = sorted_list_difference(expected, actual)
|
||||||
errors = []
|
errors = []
|
||||||
if missing:
|
if missing:
|
||||||
errors.append('Expected, but missing:\n %r' % missing)
|
errors.append('Expected, but missing:\n %s' %
|
||||||
|
safe_repr(missing))
|
||||||
if unexpected:
|
if unexpected:
|
||||||
errors.append('Unexpected, but present:\n %r' % unexpected)
|
errors.append('Unexpected, but present:\n %s' %
|
||||||
|
safe_repr(unexpected))
|
||||||
if errors:
|
if errors:
|
||||||
standardMsg = '\n'.join(errors)
|
standardMsg = '\n'.join(errors)
|
||||||
self.fail(self._formatMessage(msg, standardMsg))
|
self.fail(self._formatMessage(msg, standardMsg))
|
||||||
@ -800,31 +853,31 @@ class TestCase(object):
|
|||||||
def assertLess(self, a, b, msg=None):
|
def assertLess(self, a, b, msg=None):
|
||||||
"""Just like self.assertTrue(a < b), but with a nicer default message."""
|
"""Just like self.assertTrue(a < b), but with a nicer default message."""
|
||||||
if not a < b:
|
if not a < b:
|
||||||
standardMsg = '%r not less than %r' % (a, b)
|
standardMsg = '%s not less than %s' % (safe_repr(a), safe_repr(b))
|
||||||
self.fail(self._formatMessage(msg, standardMsg))
|
self.fail(self._formatMessage(msg, standardMsg))
|
||||||
|
|
||||||
def assertLessEqual(self, a, b, msg=None):
|
def assertLessEqual(self, a, b, msg=None):
|
||||||
"""Just like self.assertTrue(a <= b), but with a nicer default message."""
|
"""Just like self.assertTrue(a <= b), but with a nicer default message."""
|
||||||
if not a <= b:
|
if not a <= b:
|
||||||
standardMsg = '%r not less than or equal to %r' % (a, b)
|
standardMsg = '%s not less than or equal to %s' % (safe_repr(a), safe_repr(b))
|
||||||
self.fail(self._formatMessage(msg, standardMsg))
|
self.fail(self._formatMessage(msg, standardMsg))
|
||||||
|
|
||||||
def assertGreater(self, a, b, msg=None):
|
def assertGreater(self, a, b, msg=None):
|
||||||
"""Just like self.assertTrue(a > b), but with a nicer default message."""
|
"""Just like self.assertTrue(a > b), but with a nicer default message."""
|
||||||
if not a > b:
|
if not a > b:
|
||||||
standardMsg = '%r not greater than %r' % (a, b)
|
standardMsg = '%s not greater than %s' % (safe_repr(a), safe_repr(b))
|
||||||
self.fail(self._formatMessage(msg, standardMsg))
|
self.fail(self._formatMessage(msg, standardMsg))
|
||||||
|
|
||||||
def assertGreaterEqual(self, a, b, msg=None):
|
def assertGreaterEqual(self, a, b, msg=None):
|
||||||
"""Just like self.assertTrue(a >= b), but with a nicer default message."""
|
"""Just like self.assertTrue(a >= b), but with a nicer default message."""
|
||||||
if not a >= b:
|
if not a >= b:
|
||||||
standardMsg = '%r not greater than or equal to %r' % (a, b)
|
standardMsg = '%s not greater than or equal to %s' % (safe_repr(a), safe_repr(b))
|
||||||
self.fail(self._formatMessage(msg, standardMsg))
|
self.fail(self._formatMessage(msg, standardMsg))
|
||||||
|
|
||||||
def assertIsNone(self, obj, msg=None):
|
def assertIsNone(self, obj, msg=None):
|
||||||
"""Same as self.assertTrue(obj is None), with a nicer default message."""
|
"""Same as self.assertTrue(obj is None), with a nicer default message."""
|
||||||
if obj is not None:
|
if obj is not None:
|
||||||
standardMsg = '%r is not None' % obj
|
standardMsg = '%s is not None' % (safe_repr(obj),)
|
||||||
self.fail(self._formatMessage(msg, standardMsg))
|
self.fail(self._formatMessage(msg, standardMsg))
|
||||||
|
|
||||||
def assertIsNotNone(self, obj, msg=None):
|
def assertIsNotNone(self, obj, msg=None):
|
||||||
@ -837,13 +890,13 @@ class TestCase(object):
|
|||||||
"""Same as self.assertTrue(isinstance(obj, cls)), with a nicer
|
"""Same as self.assertTrue(isinstance(obj, cls)), with a nicer
|
||||||
default message."""
|
default message."""
|
||||||
if not isinstance(obj, cls):
|
if not isinstance(obj, cls):
|
||||||
standardMsg = '%r is not an instance of %r' % (obj, cls)
|
standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls)
|
||||||
self.fail(self._formatMessage(msg, standardMsg))
|
self.fail(self._formatMessage(msg, standardMsg))
|
||||||
|
|
||||||
def assertNotIsInstance(self, obj, cls, msg=None):
|
def assertNotIsInstance(self, obj, cls, msg=None):
|
||||||
"""Included for symmetry with assertIsInstance."""
|
"""Included for symmetry with assertIsInstance."""
|
||||||
if isinstance(obj, cls):
|
if isinstance(obj, cls):
|
||||||
standardMsg = '%r is an instance of %r' % (obj, cls)
|
standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls)
|
||||||
self.fail(self._formatMessage(msg, standardMsg))
|
self.fail(self._formatMessage(msg, standardMsg))
|
||||||
|
|
||||||
def assertRaisesRegexp(self, expected_exception, expected_regexp,
|
def assertRaisesRegexp(self, expected_exception, expected_regexp,
|
||||||
@ -921,11 +974,11 @@ class FunctionTestCase(TestCase):
|
|||||||
self._testFunc, self._description))
|
self._testFunc, self._description))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "%s (%s)" % (util.strclass(self.__class__),
|
return "%s (%s)" % (strclass(self.__class__),
|
||||||
self._testFunc.__name__)
|
self._testFunc.__name__)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s testFunc=%s>" % (util.strclass(self.__class__),
|
return "<%s tec=%s>" % (strclass(self.__class__),
|
||||||
self._testFunc)
|
self._testFunc)
|
||||||
|
|
||||||
def shortDescription(self):
|
def shortDescription(self):
|
||||||
|
@ -16,7 +16,9 @@ class TestResult(object):
|
|||||||
contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
|
contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
|
||||||
formatted traceback of the error that occurred.
|
formatted traceback of the error that occurred.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
_previousTestClass = None
|
||||||
|
_moduleSetUpFailed = False
|
||||||
|
def __init__(self, stream=None, descriptions=None, verbosity=None):
|
||||||
self.failures = []
|
self.failures = []
|
||||||
self.errors = []
|
self.errors = []
|
||||||
self.testsRun = 0
|
self.testsRun = 0
|
||||||
@ -25,6 +27,9 @@ class TestResult(object):
|
|||||||
self.unexpectedSuccesses = []
|
self.unexpectedSuccesses = []
|
||||||
self.shouldStop = False
|
self.shouldStop = False
|
||||||
|
|
||||||
|
def printErrors(self):
|
||||||
|
"Called by TestRunner after test run"
|
||||||
|
|
||||||
def startTest(self, test):
|
def startTest(self, test):
|
||||||
"Called when the given test is about to be run"
|
"Called when the given test is about to be run"
|
||||||
self.testsRun += 1
|
self.testsRun += 1
|
||||||
@ -107,6 +112,6 @@ class TestResult(object):
|
|||||||
return length
|
return length
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s run=%i errors=%i failures=%i>" % \
|
return ("<%s run=%i errors=%i failures=%i>" %
|
||||||
(util.strclass(self.__class__), self.testsRun, len(self.errors),
|
(util.strclass(self.__class__), self.testsRun, len(self.errors),
|
||||||
len(self.failures))
|
len(self.failures)))
|
||||||
|
@ -148,15 +148,22 @@ class TextTestRunner(object):
|
|||||||
stopTime = time.time()
|
stopTime = time.time()
|
||||||
timeTaken = stopTime - startTime
|
timeTaken = stopTime - startTime
|
||||||
result.printErrors()
|
result.printErrors()
|
||||||
self.stream.writeln(result.separator2)
|
if hasattr(result, 'separator2'):
|
||||||
|
self.stream.writeln(result.separator2)
|
||||||
run = result.testsRun
|
run = result.testsRun
|
||||||
self.stream.writeln("Ran %d test%s in %.3fs" %
|
self.stream.writeln("Ran %d test%s in %.3fs" %
|
||||||
(run, run != 1 and "s" or "", timeTaken))
|
(run, run != 1 and "s" or "", timeTaken))
|
||||||
self.stream.writeln()
|
self.stream.writeln()
|
||||||
results = map(len, (result.expectedFailures,
|
|
||||||
result.unexpectedSuccesses,
|
expectedFails = unexpectedSuccesses = skipped = 0
|
||||||
result.skipped))
|
try:
|
||||||
expectedFails, unexpectedSuccesses, skipped = results
|
results = map(len, (result.expectedFailures,
|
||||||
|
result.unexpectedSuccesses,
|
||||||
|
result.skipped))
|
||||||
|
expectedFails, unexpectedSuccesses, skipped = results
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
infos = []
|
infos = []
|
||||||
if not result.wasSuccessful():
|
if not result.wasSuccessful():
|
||||||
self.stream.write("FAILED")
|
self.stream.write("FAILED")
|
||||||
|
@ -1,17 +1,13 @@
|
|||||||
"""TestSuite"""
|
"""TestSuite"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
from . import case
|
from . import case
|
||||||
from . import util
|
from . import util
|
||||||
|
|
||||||
|
|
||||||
class TestSuite(object):
|
class BaseTestSuite(object):
|
||||||
"""A test suite is a composite test consisting of a number of TestCases.
|
"""A simple test suite that doesn't provide class or module shared fixtures.
|
||||||
|
|
||||||
For use, create an instance of TestSuite, then add test case instances.
|
|
||||||
When all tests have been added, the suite can be passed to a test
|
|
||||||
runner, such as TextTestRunner. It will run the individual test cases
|
|
||||||
in the order in which they were added, aggregating the results. When
|
|
||||||
subclassing, do not forget to call the base class constructor.
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, tests=()):
|
def __init__(self, tests=()):
|
||||||
self._tests = []
|
self._tests = []
|
||||||
@ -67,3 +63,190 @@ class TestSuite(object):
|
|||||||
"""Run the tests without collecting errors in a TestResult"""
|
"""Run the tests without collecting errors in a TestResult"""
|
||||||
for test in self:
|
for test in self:
|
||||||
test.debug()
|
test.debug()
|
||||||
|
|
||||||
|
|
||||||
|
class TestSuite(BaseTestSuite):
|
||||||
|
"""A test suite is a composite test consisting of a number of TestCases.
|
||||||
|
|
||||||
|
For use, create an instance of TestSuite, then add test case instances.
|
||||||
|
When all tests have been added, the suite can be passed to a test
|
||||||
|
runner, such as TextTestRunner. It will run the individual test cases
|
||||||
|
in the order in which they were added, aggregating the results. When
|
||||||
|
subclassing, do not forget to call the base class constructor.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def run(self, result):
|
||||||
|
self._wrapped_run(result)
|
||||||
|
self._tearDownPreviousClass(None, result)
|
||||||
|
self._handleModuleTearDown(result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
################################
|
||||||
|
# private methods
|
||||||
|
def _wrapped_run(self, result):
|
||||||
|
for test in self:
|
||||||
|
if result.shouldStop:
|
||||||
|
break
|
||||||
|
|
||||||
|
if _isnotsuite(test):
|
||||||
|
self._tearDownPreviousClass(test, result)
|
||||||
|
self._handleModuleFixture(test, result)
|
||||||
|
self._handleClassSetUp(test, result)
|
||||||
|
result._previousTestClass = test.__class__
|
||||||
|
|
||||||
|
if (getattr(test.__class__, '_classSetupFailed', False) or
|
||||||
|
getattr(result, '_moduleSetUpFailed', False)):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if hasattr(test, '_wrapped_run'):
|
||||||
|
test._wrapped_run(result)
|
||||||
|
else:
|
||||||
|
test(result)
|
||||||
|
|
||||||
|
def _handleClassSetUp(self, test, result):
|
||||||
|
previousClass = getattr(result, '_previousTestClass', None)
|
||||||
|
currentClass = test.__class__
|
||||||
|
if currentClass == previousClass:
|
||||||
|
return
|
||||||
|
if result._moduleSetUpFailed:
|
||||||
|
return
|
||||||
|
if getattr(currentClass, "__unittest_skip__", False):
|
||||||
|
return
|
||||||
|
|
||||||
|
currentClass._classSetupFailed = False
|
||||||
|
|
||||||
|
setUpClass = getattr(currentClass, 'setUpClass', None)
|
||||||
|
if setUpClass is not None:
|
||||||
|
try:
|
||||||
|
setUpClass()
|
||||||
|
except:
|
||||||
|
currentClass._classSetupFailed = True
|
||||||
|
self._addClassSetUpError(result, currentClass)
|
||||||
|
|
||||||
|
def _get_previous_module(self, result):
|
||||||
|
previousModule = None
|
||||||
|
previousClass = getattr(result, '_previousTestClass', None)
|
||||||
|
if previousClass is not None:
|
||||||
|
previousModule = previousClass.__module__
|
||||||
|
return previousModule
|
||||||
|
|
||||||
|
|
||||||
|
def _handleModuleFixture(self, test, result):
|
||||||
|
previousModule = self._get_previous_module(result)
|
||||||
|
currentModule = test.__class__.__module__
|
||||||
|
if currentModule == previousModule:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._handleModuleTearDown(result)
|
||||||
|
|
||||||
|
|
||||||
|
result._moduleSetUpFailed = False
|
||||||
|
try:
|
||||||
|
module = sys.modules[currentModule]
|
||||||
|
except KeyError:
|
||||||
|
return
|
||||||
|
setUpModule = getattr(module, 'setUpModule', None)
|
||||||
|
if setUpModule is not None:
|
||||||
|
try:
|
||||||
|
setUpModule()
|
||||||
|
except:
|
||||||
|
result._moduleSetUpFailed = True
|
||||||
|
error = _ErrorHolder('setUpModule (%s)' % currentModule)
|
||||||
|
result.addError(error, sys.exc_info())
|
||||||
|
|
||||||
|
def _handleModuleTearDown(self, result):
|
||||||
|
previousModule = self._get_previous_module(result)
|
||||||
|
if previousModule is None:
|
||||||
|
return
|
||||||
|
if result._moduleSetUpFailed:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
module = sys.modules[previousModule]
|
||||||
|
except KeyError:
|
||||||
|
return
|
||||||
|
|
||||||
|
tearDownModule = getattr(module, 'tearDownModule', None)
|
||||||
|
if tearDownModule is not None:
|
||||||
|
try:
|
||||||
|
tearDownModule()
|
||||||
|
except:
|
||||||
|
error = _ErrorHolder('tearDownModule (%s)' % previousModule)
|
||||||
|
result.addError(error, sys.exc_info())
|
||||||
|
|
||||||
|
def _tearDownPreviousClass(self, test, result):
|
||||||
|
previousClass = getattr(result, '_previousTestClass', None)
|
||||||
|
currentClass = test.__class__
|
||||||
|
if currentClass == previousClass:
|
||||||
|
return
|
||||||
|
if getattr(previousClass, '_classSetupFailed', False):
|
||||||
|
return
|
||||||
|
if getattr(result, '_moduleSetUpFailed', False):
|
||||||
|
return
|
||||||
|
if getattr(previousClass, "__unittest_skip__", False):
|
||||||
|
return
|
||||||
|
|
||||||
|
tearDownClass = getattr(previousClass, 'tearDownClass', None)
|
||||||
|
if tearDownClass is not None:
|
||||||
|
try:
|
||||||
|
tearDownClass()
|
||||||
|
except:
|
||||||
|
self._addClassTearDownError(result)
|
||||||
|
|
||||||
|
def _addClassTearDownError(self, result):
|
||||||
|
className = util.strclass(result._previousTestClass)
|
||||||
|
error = _ErrorHolder('classTearDown (%s)' % className)
|
||||||
|
result.addError(error, sys.exc_info())
|
||||||
|
|
||||||
|
def _addClassSetUpError(self, result, klass):
|
||||||
|
className = util.strclass(klass)
|
||||||
|
error = _ErrorHolder('classSetUp (%s)' % className)
|
||||||
|
result.addError(error, sys.exc_info())
|
||||||
|
|
||||||
|
|
||||||
|
class _ErrorHolder(object):
|
||||||
|
"""
|
||||||
|
Placeholder for a TestCase inside a result. As far as a TestResult
|
||||||
|
is concerned, this looks exactly like a unit test. Used to insert
|
||||||
|
arbitrary errors into a test suite run.
|
||||||
|
"""
|
||||||
|
# Inspired by the ErrorHolder from Twisted:
|
||||||
|
# http://twistedmatrix.com/trac/browser/trunk/twisted/trial/runner.py
|
||||||
|
|
||||||
|
# attribute used by TestResult._exc_info_to_string
|
||||||
|
failureException = None
|
||||||
|
|
||||||
|
def __init__(self, description):
|
||||||
|
self.description = description
|
||||||
|
|
||||||
|
def id(self):
|
||||||
|
return self.description
|
||||||
|
|
||||||
|
def shortDescription(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<ErrorHolder description=%r>" % (self.description,)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.id()
|
||||||
|
|
||||||
|
def run(self, result):
|
||||||
|
# could call result.addError(...) - but this test-like object
|
||||||
|
# shouldn't be run anyway
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __call__(self, result):
|
||||||
|
return self.run(result)
|
||||||
|
|
||||||
|
def countTestCases(self):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def _isnotsuite(test):
|
||||||
|
"A crude way to tell apart testcases and suites with duck-typing"
|
||||||
|
try:
|
||||||
|
iter(test)
|
||||||
|
except TypeError:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
"""Various utility functions."""
|
"""Various utility functions."""
|
||||||
|
|
||||||
|
def safe_repr(obj):
|
||||||
|
try:
|
||||||
|
return repr(obj)
|
||||||
|
except Exception:
|
||||||
|
return object.__repr__(obj)
|
||||||
|
|
||||||
def strclass(cls):
|
def strclass(cls):
|
||||||
return "%s.%s" % (cls.__module__, cls.__name__)
|
return "%s.%s" % (cls.__module__, cls.__name__)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user