gh-84867: Do not load tests from TestCase and FunctionTestCase (GH-100497)

This commit is contained in:
Nikita Sobolev 2023-09-12 16:33:30 +03:00 committed by GitHub
parent d13f782a18
commit 66d1d7eb06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 5 deletions

View File

@ -82,6 +82,22 @@ class Test_TestLoader(unittest.TestCase):
self.assertIsInstance(suite, loader.suiteClass)
self.assertEqual(list(suite), [Foo('runTest')])
# "Do not load any tests from `TestCase` class itself."
def test_loadTestsFromTestCase__from_TestCase(self):
loader = unittest.TestLoader()
suite = loader.loadTestsFromTestCase(unittest.TestCase)
self.assertIsInstance(suite, loader.suiteClass)
self.assertEqual(list(suite), [])
# "Do not load any tests from `FunctionTestCase` class."
def test_loadTestsFromTestCase__from_FunctionTestCase(self):
loader = unittest.TestLoader()
suite = loader.loadTestsFromTestCase(unittest.FunctionTestCase)
self.assertIsInstance(suite, loader.suiteClass)
self.assertEqual(list(suite), [])
################################################################
### /Tests for TestLoader.loadTestsFromTestCase
@ -103,6 +119,19 @@ class Test_TestLoader(unittest.TestCase):
expected = [loader.suiteClass([MyTestCase('test')])]
self.assertEqual(list(suite), expected)
# "This test ensures that internal `TestCase` subclasses are not loaded"
def test_loadTestsFromModule__TestCase_subclass_internals(self):
# See https://github.com/python/cpython/issues/84867
m = types.ModuleType('m')
# Simulate imported names:
m.TestCase = unittest.TestCase
m.FunctionTestCase = unittest.FunctionTestCase
loader = unittest.TestLoader()
suite = loader.loadTestsFromModule(m)
self.assertIsInstance(suite, loader.suiteClass)
self.assertEqual(list(suite), [])
# "This method searches `module` for classes derived from TestCase"
#
# What happens if no tests are found (no TestCase instances)?

View File

@ -84,9 +84,13 @@ class TestLoader(object):
raise TypeError("Test cases should not be derived from "
"TestSuite. Maybe you meant to derive from "
"TestCase?")
testCaseNames = self.getTestCaseNames(testCaseClass)
if not testCaseNames and hasattr(testCaseClass, 'runTest'):
testCaseNames = ['runTest']
if testCaseClass in (case.TestCase, case.FunctionTestCase):
# We don't load any tests from base types that should not be loaded.
testCaseNames = []
else:
testCaseNames = self.getTestCaseNames(testCaseClass)
if not testCaseNames and hasattr(testCaseClass, 'runTest'):
testCaseNames = ['runTest']
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
return loaded_suite
@ -95,7 +99,11 @@ class TestLoader(object):
tests = []
for name in dir(module):
obj = getattr(module, name)
if isinstance(obj, type) and issubclass(obj, case.TestCase):
if (
isinstance(obj, type)
and issubclass(obj, case.TestCase)
and obj not in (case.TestCase, case.FunctionTestCase)
):
tests.append(self.loadTestsFromTestCase(obj))
load_tests = getattr(module, 'load_tests', None)
@ -164,7 +172,11 @@ class TestLoader(object):
if isinstance(obj, types.ModuleType):
return self.loadTestsFromModule(obj)
elif isinstance(obj, type) and issubclass(obj, case.TestCase):
elif (
isinstance(obj, type)
and issubclass(obj, case.TestCase)
and obj not in (case.TestCase, case.FunctionTestCase)
):
return self.loadTestsFromTestCase(obj)
elif (isinstance(obj, types.FunctionType) and
isinstance(parent, type) and

View File

@ -0,0 +1,2 @@
:class:`unittest.TestLoader` no longer loads test cases from exact
:class:`unittest.TestCase` and :class:`unittest.FunctionTestCase` classes.