summaryrefslogtreecommitdiff
path: root/Lib/unittest/test/test_loader.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/unittest/test/test_loader.py')
-rw-r--r--Lib/unittest/test/test_loader.py423
1 files changed, 319 insertions, 104 deletions
diff --git a/Lib/unittest/test/test_loader.py b/Lib/unittest/test/test_loader.py
index b62a1b5c54..68f1036111 100644
--- a/Lib/unittest/test/test_loader.py
+++ b/Lib/unittest/test/test_loader.py
@@ -1,12 +1,36 @@
import sys
import types
-
+import warnings
import unittest
+# Decorator used in the deprecation tests to reset the warning registry for
+# test isolation and reproducibility.
+def warningregistry(func):
+ def wrapper(*args, **kws):
+ missing = object()
+ saved = getattr(warnings, '__warningregistry__', missing).copy()
+ try:
+ return func(*args, **kws)
+ finally:
+ if saved is missing:
+ try:
+ del warnings.__warningregistry__
+ except AttributeError:
+ pass
+ else:
+ warnings.__warningregistry__ = saved
+
class Test_TestLoader(unittest.TestCase):
+ ### Basic object tests
+ ################################################################
+
+ def test___init__(self):
+ loader = unittest.TestLoader()
+ self.assertEqual([], loader.errors)
+
### Tests for TestLoader.loadTestsFromTestCase
################################################################
@@ -150,6 +174,7 @@ class Test_TestLoader(unittest.TestCase):
# Check that loadTestsFromModule honors (or not) a module
# with a load_tests function.
+ @warningregistry
def test_loadTestsFromModule__load_tests(self):
m = types.ModuleType('m')
class MyTestCase(unittest.TestCase):
@@ -168,10 +193,144 @@ class Test_TestLoader(unittest.TestCase):
suite = loader.loadTestsFromModule(m)
self.assertIsInstance(suite, unittest.TestSuite)
self.assertEqual(load_tests_args, [loader, suite, None])
+ # With Python 3.5, the undocumented and unofficial use_load_tests is
+ # ignored (and deprecated).
+ load_tests_args = []
+ with warnings.catch_warnings(record=False):
+ warnings.simplefilter('never')
+ suite = loader.loadTestsFromModule(m, use_load_tests=False)
+ self.assertEqual(load_tests_args, [loader, suite, None])
+
+ @warningregistry
+ def test_loadTestsFromModule__use_load_tests_deprecated_positional(self):
+ m = types.ModuleType('m')
+ class MyTestCase(unittest.TestCase):
+ def test(self):
+ pass
+ m.testcase_1 = MyTestCase
+
+ load_tests_args = []
+ def load_tests(loader, tests, pattern):
+ self.assertIsInstance(tests, unittest.TestSuite)
+ load_tests_args.extend((loader, tests, pattern))
+ return tests
+ m.load_tests = load_tests
+ # The method still works.
+ loader = unittest.TestLoader()
+ # use_load_tests=True as a positional argument.
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter('always')
+ suite = loader.loadTestsFromModule(m, False)
+ self.assertIsInstance(suite, unittest.TestSuite)
+ # load_tests was still called because use_load_tests is deprecated
+ # and ignored.
+ self.assertEqual(load_tests_args, [loader, suite, None])
+ # We got a warning.
+ self.assertIs(w[-1].category, DeprecationWarning)
+ self.assertEqual(str(w[-1].message),
+ 'use_load_tests is deprecated and ignored')
+
+ @warningregistry
+ def test_loadTestsFromModule__use_load_tests_deprecated_keyword(self):
+ m = types.ModuleType('m')
+ class MyTestCase(unittest.TestCase):
+ def test(self):
+ pass
+ m.testcase_1 = MyTestCase
+
+ load_tests_args = []
+ def load_tests(loader, tests, pattern):
+ self.assertIsInstance(tests, unittest.TestSuite)
+ load_tests_args.extend((loader, tests, pattern))
+ return tests
+ m.load_tests = load_tests
+ # The method still works.
+ loader = unittest.TestLoader()
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter('always')
+ suite = loader.loadTestsFromModule(m, use_load_tests=False)
+ self.assertIsInstance(suite, unittest.TestSuite)
+ # load_tests was still called because use_load_tests is deprecated
+ # and ignored.
+ self.assertEqual(load_tests_args, [loader, suite, None])
+ # We got a warning.
+ self.assertIs(w[-1].category, DeprecationWarning)
+ self.assertEqual(str(w[-1].message),
+ 'use_load_tests is deprecated and ignored')
+
+ @warningregistry
+ def test_loadTestsFromModule__too_many_positional_args(self):
+ m = types.ModuleType('m')
+ class MyTestCase(unittest.TestCase):
+ def test(self):
+ pass
+ m.testcase_1 = MyTestCase
load_tests_args = []
- suite = loader.loadTestsFromModule(m, use_load_tests=False)
- self.assertEqual(load_tests_args, [])
+ def load_tests(loader, tests, pattern):
+ self.assertIsInstance(tests, unittest.TestSuite)
+ load_tests_args.extend((loader, tests, pattern))
+ return tests
+ m.load_tests = load_tests
+ loader = unittest.TestLoader()
+ with self.assertRaises(TypeError) as cm, \
+ warnings.catch_warning(record=True) as w:
+ loader.loadTestsFromModule(m, False, 'testme.*')
+ # We still got the deprecation warning.
+ self.assertIs(w[-1].category, DeprecationWarning)
+ self.assertEqual(str(w[-1].message),
+ 'use_load_tests is deprecated and ignored')
+ # We also got a TypeError for too many positional arguments.
+ self.assertEqual(type(cm.exception), TypeError)
+ self.assertEqual(
+ str(cm.exception),
+ 'loadTestsFromModule() takes 1 positional argument but 3 were given')
+
+ @warningregistry
+ def test_loadTestsFromModule__use_load_tests_other_bad_keyword(self):
+ m = types.ModuleType('m')
+ class MyTestCase(unittest.TestCase):
+ def test(self):
+ pass
+ m.testcase_1 = MyTestCase
+
+ load_tests_args = []
+ def load_tests(loader, tests, pattern):
+ self.assertIsInstance(tests, unittest.TestSuite)
+ load_tests_args.extend((loader, tests, pattern))
+ return tests
+ m.load_tests = load_tests
+ loader = unittest.TestLoader()
+ with warnings.catch_warnings():
+ warnings.simplefilter('never')
+ with self.assertRaises(TypeError) as cm:
+ loader.loadTestsFromModule(
+ m, use_load_tests=False, very_bad=True, worse=False)
+ self.assertEqual(type(cm.exception), TypeError)
+ # The error message names the first bad argument alphabetically,
+ # however use_load_tests (which sorts first) is ignored.
+ self.assertEqual(
+ str(cm.exception),
+ "loadTestsFromModule() got an unexpected keyword argument 'very_bad'")
+
+ def test_loadTestsFromModule__pattern(self):
+ m = types.ModuleType('m')
+ class MyTestCase(unittest.TestCase):
+ def test(self):
+ pass
+ m.testcase_1 = MyTestCase
+
+ load_tests_args = []
+ def load_tests(loader, tests, pattern):
+ self.assertIsInstance(tests, unittest.TestSuite)
+ load_tests_args.extend((loader, tests, pattern))
+ return tests
+ m.load_tests = load_tests
+
+ loader = unittest.TestLoader()
+ suite = loader.loadTestsFromModule(m, pattern='testme.*')
+ self.assertIsInstance(suite, unittest.TestSuite)
+ self.assertEqual(load_tests_args, [loader, suite, 'testme.*'])
def test_loadTestsFromModule__faulty_load_tests(self):
m = types.ModuleType('m')
@@ -184,6 +343,13 @@ class Test_TestLoader(unittest.TestCase):
suite = loader.loadTestsFromModule(m)
self.assertIsInstance(suite, unittest.TestSuite)
self.assertEqual(suite.countTestCases(), 1)
+ # Errors loading the suite are also captured for introspection.
+ self.assertNotEqual([], loader.errors)
+ self.assertEqual(1, len(loader.errors))
+ error = loader.errors[0]
+ self.assertTrue(
+ 'Failed to call load_tests:' in error,
+ 'missing error string in %r' % error)
test = list(suite)[0]
self.assertRaisesRegex(TypeError, "some failure", test.m)
@@ -219,15 +385,15 @@ class Test_TestLoader(unittest.TestCase):
def test_loadTestsFromName__malformed_name(self):
loader = unittest.TestLoader()
- # XXX Should this raise ValueError or ImportError?
- try:
- loader.loadTestsFromName('abc () //')
- except ValueError:
- pass
- except ImportError:
- pass
- else:
- self.fail("TestLoader.loadTestsFromName failed to raise ValueError")
+ suite = loader.loadTestsFromName('abc () //')
+ error, test = self.check_deferred_error(loader, suite)
+ expected = "Failed to import test module: abc () //"
+ expected_regex = "Failed to import test module: abc \(\) //"
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(
+ ImportError, expected_regex, getattr(test, 'abc () //'))
# "The specifier name is a ``dotted name'' that may resolve ... to a
# module"
@@ -236,28 +402,47 @@ class Test_TestLoader(unittest.TestCase):
def test_loadTestsFromName__unknown_module_name(self):
loader = unittest.TestLoader()
- try:
- loader.loadTestsFromName('sdasfasfasdf')
- except ImportError as e:
- self.assertEqual(str(e), "No module named 'sdasfasfasdf'")
- else:
- self.fail("TestLoader.loadTestsFromName failed to raise ImportError")
+ suite = loader.loadTestsFromName('sdasfasfasdf')
+ expected = "No module named 'sdasfasfasdf'"
+ error, test = self.check_deferred_error(loader, suite)
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(ImportError, expected, test.sdasfasfasdf)
# "The specifier name is a ``dotted name'' that may resolve either to
# a module, a test case class, a TestSuite instance, a test method
# within a test case class, or a callable object which returns a
# TestCase or TestSuite instance."
#
- # What happens when the module is found, but the attribute can't?
- def test_loadTestsFromName__unknown_attr_name(self):
+ # What happens when the module is found, but the attribute isn't?
+ def test_loadTestsFromName__unknown_attr_name_on_module(self):
loader = unittest.TestLoader()
- try:
- loader.loadTestsFromName('unittest.sdasfasfasdf')
- except AttributeError as e:
- self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
- else:
- self.fail("TestLoader.loadTestsFromName failed to raise AttributeError")
+ suite = loader.loadTestsFromName('unittest.loader.sdasfasfasdf')
+ expected = "module 'unittest.loader' has no attribute 'sdasfasfasdf'"
+ error, test = self.check_deferred_error(loader, suite)
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(AttributeError, expected, test.sdasfasfasdf)
+
+ # "The specifier name is a ``dotted name'' that may resolve either to
+ # a module, a test case class, a TestSuite instance, a test method
+ # within a test case class, or a callable object which returns a
+ # TestCase or TestSuite instance."
+ #
+ # What happens when the module is found, but the attribute isn't?
+ def test_loadTestsFromName__unknown_attr_name_on_package(self):
+ loader = unittest.TestLoader()
+
+ suite = loader.loadTestsFromName('unittest.sdasfasfasdf')
+ expected = "No module named 'unittest.sdasfasfasdf'"
+ error, test = self.check_deferred_error(loader, suite)
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(ImportError, expected, test.sdasfasfasdf)
# "The specifier name is a ``dotted name'' that may resolve either to
# a module, a test case class, a TestSuite instance, a test method
@@ -269,12 +454,13 @@ class Test_TestLoader(unittest.TestCase):
def test_loadTestsFromName__relative_unknown_name(self):
loader = unittest.TestLoader()
- try:
- loader.loadTestsFromName('sdasfasfasdf', unittest)
- except AttributeError as e:
- self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
- else:
- self.fail("TestLoader.loadTestsFromName failed to raise AttributeError")
+ suite = loader.loadTestsFromName('sdasfasfasdf', unittest)
+ expected = "module 'unittest' has no attribute 'sdasfasfasdf'"
+ error, test = self.check_deferred_error(loader, suite)
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(AttributeError, expected, test.sdasfasfasdf)
# "The specifier name is a ``dotted name'' that may resolve either to
# a module, a test case class, a TestSuite instance, a test method
@@ -290,12 +476,13 @@ class Test_TestLoader(unittest.TestCase):
def test_loadTestsFromName__relative_empty_name(self):
loader = unittest.TestLoader()
- try:
- loader.loadTestsFromName('', unittest)
- except AttributeError as e:
- pass
- else:
- self.fail("Failed to raise AttributeError")
+ suite = loader.loadTestsFromName('', unittest)
+ error, test = self.check_deferred_error(loader, suite)
+ expected = "has no attribute ''"
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(AttributeError, expected, getattr(test, ''))
# "The specifier name is a ``dotted name'' that may resolve either to
# a module, a test case class, a TestSuite instance, a test method
@@ -310,14 +497,15 @@ class Test_TestLoader(unittest.TestCase):
loader = unittest.TestLoader()
# XXX Should this raise AttributeError or ValueError?
- try:
- loader.loadTestsFromName('abc () //', unittest)
- except ValueError:
- pass
- except AttributeError:
- pass
- else:
- self.fail("TestLoader.loadTestsFromName failed to raise ValueError")
+ suite = loader.loadTestsFromName('abc () //', unittest)
+ error, test = self.check_deferred_error(loader, suite)
+ expected = "module 'unittest' has no attribute 'abc () //'"
+ expected_regex = "module 'unittest' has no attribute 'abc \(\) //'"
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(
+ AttributeError, expected_regex, getattr(test, 'abc () //'))
# "The method optionally resolves name relative to the given module"
#
@@ -423,12 +611,13 @@ class Test_TestLoader(unittest.TestCase):
m.testcase_1 = MyTestCase
loader = unittest.TestLoader()
- try:
- loader.loadTestsFromName('testcase_1.testfoo', m)
- except AttributeError as e:
- self.assertEqual(str(e), "type object 'MyTestCase' has no attribute 'testfoo'")
- else:
- self.fail("Failed to raise AttributeError")
+ suite = loader.loadTestsFromName('testcase_1.testfoo', m)
+ expected = "type object 'MyTestCase' has no attribute 'testfoo'"
+ error, test = self.check_deferred_error(loader, suite)
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(AttributeError, expected, test.testfoo)
# "The specifier name is a ``dotted name'' that may resolve ... to
# ... a callable object which returns a ... TestSuite instance"
@@ -546,6 +735,23 @@ class Test_TestLoader(unittest.TestCase):
### Tests for TestLoader.loadTestsFromNames()
################################################################
+ def check_deferred_error(self, loader, suite):
+ """Helper function for checking that errors in loading are reported.
+
+ :param loader: A loader with some errors.
+ :param suite: A suite that should have a late bound error.
+ :return: The first error message from the loader and the test object
+ from the suite.
+ """
+ self.assertIsInstance(suite, unittest.TestSuite)
+ self.assertEqual(suite.countTestCases(), 1)
+ # Errors loading the suite are also captured for introspection.
+ self.assertNotEqual([], loader.errors)
+ self.assertEqual(1, len(loader.errors))
+ error = loader.errors[0]
+ test = list(suite)[0]
+ return error, test
+
# "Similar to loadTestsFromName(), but takes a sequence of names rather
# than a single name."
#
@@ -598,14 +804,15 @@ class Test_TestLoader(unittest.TestCase):
loader = unittest.TestLoader()
# XXX Should this raise ValueError or ImportError?
- try:
- loader.loadTestsFromNames(['abc () //'])
- except ValueError:
- pass
- except ImportError:
- pass
- else:
- self.fail("TestLoader.loadTestsFromNames failed to raise ValueError")
+ suite = loader.loadTestsFromNames(['abc () //'])
+ error, test = self.check_deferred_error(loader, list(suite)[0])
+ expected = "Failed to import test module: abc () //"
+ expected_regex = "Failed to import test module: abc \(\) //"
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(
+ ImportError, expected_regex, getattr(test, 'abc () //'))
# "The specifier name is a ``dotted name'' that may resolve either to
# a module, a test case class, a TestSuite instance, a test method
@@ -616,12 +823,13 @@ class Test_TestLoader(unittest.TestCase):
def test_loadTestsFromNames__unknown_module_name(self):
loader = unittest.TestLoader()
- try:
- loader.loadTestsFromNames(['sdasfasfasdf'])
- except ImportError as e:
- self.assertEqual(str(e), "No module named 'sdasfasfasdf'")
- else:
- self.fail("TestLoader.loadTestsFromNames failed to raise ImportError")
+ suite = loader.loadTestsFromNames(['sdasfasfasdf'])
+ error, test = self.check_deferred_error(loader, list(suite)[0])
+ expected = "Failed to import test module: sdasfasfasdf"
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(ImportError, expected, test.sdasfasfasdf)
# "The specifier name is a ``dotted name'' that may resolve either to
# a module, a test case class, a TestSuite instance, a test method
@@ -632,12 +840,14 @@ class Test_TestLoader(unittest.TestCase):
def test_loadTestsFromNames__unknown_attr_name(self):
loader = unittest.TestLoader()
- try:
- loader.loadTestsFromNames(['unittest.sdasfasfasdf', 'unittest'])
- except AttributeError as e:
- self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
- else:
- self.fail("TestLoader.loadTestsFromNames failed to raise AttributeError")
+ suite = loader.loadTestsFromNames(
+ ['unittest.loader.sdasfasfasdf', 'unittest.test.dummy'])
+ error, test = self.check_deferred_error(loader, list(suite)[0])
+ expected = "module 'unittest.loader' has no attribute 'sdasfasfasdf'"
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(AttributeError, expected, test.sdasfasfasdf)
# "The specifier name is a ``dotted name'' that may resolve either to
# a module, a test case class, a TestSuite instance, a test method
@@ -651,12 +861,13 @@ class Test_TestLoader(unittest.TestCase):
def test_loadTestsFromNames__unknown_name_relative_1(self):
loader = unittest.TestLoader()
- try:
- loader.loadTestsFromNames(['sdasfasfasdf'], unittest)
- except AttributeError as e:
- self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
- else:
- self.fail("TestLoader.loadTestsFromName failed to raise AttributeError")
+ suite = loader.loadTestsFromNames(['sdasfasfasdf'], unittest)
+ error, test = self.check_deferred_error(loader, list(suite)[0])
+ expected = "module 'unittest' has no attribute 'sdasfasfasdf'"
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(AttributeError, expected, test.sdasfasfasdf)
# "The specifier name is a ``dotted name'' that may resolve either to
# a module, a test case class, a TestSuite instance, a test method
@@ -670,12 +881,13 @@ class Test_TestLoader(unittest.TestCase):
def test_loadTestsFromNames__unknown_name_relative_2(self):
loader = unittest.TestLoader()
- try:
- loader.loadTestsFromNames(['TestCase', 'sdasfasfasdf'], unittest)
- except AttributeError as e:
- self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'")
- else:
- self.fail("TestLoader.loadTestsFromName failed to raise AttributeError")
+ suite = loader.loadTestsFromNames(['TestCase', 'sdasfasfasdf'], unittest)
+ error, test = self.check_deferred_error(loader, list(suite)[1])
+ expected = "module 'unittest' has no attribute 'sdasfasfasdf'"
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(AttributeError, expected, test.sdasfasfasdf)
# "The specifier name is a ``dotted name'' that may resolve either to
# a module, a test case class, a TestSuite instance, a test method
@@ -691,12 +903,13 @@ class Test_TestLoader(unittest.TestCase):
def test_loadTestsFromNames__relative_empty_name(self):
loader = unittest.TestLoader()
- try:
- loader.loadTestsFromNames([''], unittest)
- except AttributeError:
- pass
- else:
- self.fail("Failed to raise ValueError")
+ suite = loader.loadTestsFromNames([''], unittest)
+ error, test = self.check_deferred_error(loader, list(suite)[0])
+ expected = "has no attribute ''"
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(AttributeError, expected, getattr(test, ''))
# "The specifier name is a ``dotted name'' that may resolve either to
# a module, a test case class, a TestSuite instance, a test method
@@ -710,14 +923,15 @@ class Test_TestLoader(unittest.TestCase):
loader = unittest.TestLoader()
# XXX Should this raise AttributeError or ValueError?
- try:
- loader.loadTestsFromNames(['abc () //'], unittest)
- except AttributeError:
- pass
- except ValueError:
- pass
- else:
- self.fail("TestLoader.loadTestsFromNames failed to raise ValueError")
+ suite = loader.loadTestsFromNames(['abc () //'], unittest)
+ error, test = self.check_deferred_error(loader, list(suite)[0])
+ expected = "module 'unittest' has no attribute 'abc () //'"
+ expected_regex = "module 'unittest' has no attribute 'abc \(\) //'"
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(
+ AttributeError, expected_regex, getattr(test, 'abc () //'))
# "The method optionally resolves name relative to the given module"
#
@@ -835,12 +1049,13 @@ class Test_TestLoader(unittest.TestCase):
m.testcase_1 = MyTestCase
loader = unittest.TestLoader()
- try:
- loader.loadTestsFromNames(['testcase_1.testfoo'], m)
- except AttributeError as e:
- self.assertEqual(str(e), "type object 'MyTestCase' has no attribute 'testfoo'")
- else:
- self.fail("Failed to raise AttributeError")
+ suite = loader.loadTestsFromNames(['testcase_1.testfoo'], m)
+ error, test = self.check_deferred_error(loader, list(suite)[0])
+ expected = "type object 'MyTestCase' has no attribute 'testfoo'"
+ self.assertIn(
+ expected, error,
+ 'missing error string in %r' % error)
+ self.assertRaisesRegex(AttributeError, expected, test.testfoo)
# "The specifier name is a ``dotted name'' that may resolve ... to
# ... a callable object which returns a ... TestSuite instance"