Skip to content

Commit b4c1cf9

Browse files
[3.11] gh-84867: Do not load tests from TestCase and FunctionTestCase (GH-100497) (GH-109328)
(cherry picked from commit 66d1d7e) Co-authored-by: Nikita Sobolev <[email protected]>
1 parent 1e86961 commit b4c1cf9

File tree

3 files changed

+48
-5
lines changed

3 files changed

+48
-5
lines changed

Lib/unittest/loader.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,13 @@ def loadTestsFromTestCase(self, testCaseClass):
8787
raise TypeError("Test cases should not be derived from "
8888
"TestSuite. Maybe you meant to derive from "
8989
"TestCase?")
90-
testCaseNames = self.getTestCaseNames(testCaseClass)
91-
if not testCaseNames and hasattr(testCaseClass, 'runTest'):
92-
testCaseNames = ['runTest']
90+
if testCaseClass in (case.TestCase, case.FunctionTestCase):
91+
# We don't load any tests from base types that should not be loaded.
92+
testCaseNames = []
93+
else:
94+
testCaseNames = self.getTestCaseNames(testCaseClass)
95+
if not testCaseNames and hasattr(testCaseClass, 'runTest'):
96+
testCaseNames = ['runTest']
9397
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
9498
return loaded_suite
9599

@@ -120,7 +124,11 @@ def loadTestsFromModule(self, module, *args, pattern=None, **kws):
120124
tests = []
121125
for name in dir(module):
122126
obj = getattr(module, name)
123-
if isinstance(obj, type) and issubclass(obj, case.TestCase):
127+
if (
128+
isinstance(obj, type)
129+
and issubclass(obj, case.TestCase)
130+
and obj not in (case.TestCase, case.FunctionTestCase)
131+
):
124132
tests.append(self.loadTestsFromTestCase(obj))
125133

126134
load_tests = getattr(module, 'load_tests', None)
@@ -189,7 +197,11 @@ def loadTestsFromName(self, name, module=None):
189197

190198
if isinstance(obj, types.ModuleType):
191199
return self.loadTestsFromModule(obj)
192-
elif isinstance(obj, type) and issubclass(obj, case.TestCase):
200+
elif (
201+
isinstance(obj, type)
202+
and issubclass(obj, case.TestCase)
203+
and obj not in (case.TestCase, case.FunctionTestCase)
204+
):
193205
return self.loadTestsFromTestCase(obj)
194206
elif (isinstance(obj, types.FunctionType) and
195207
isinstance(parent, type) and

Lib/unittest/test/test_loader.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,22 @@ def runTest(self):
102102
self.assertIsInstance(suite, loader.suiteClass)
103103
self.assertEqual(list(suite), [Foo('runTest')])
104104

105+
# "Do not load any tests from `TestCase` class itself."
106+
def test_loadTestsFromTestCase__from_TestCase(self):
107+
loader = unittest.TestLoader()
108+
109+
suite = loader.loadTestsFromTestCase(unittest.TestCase)
110+
self.assertIsInstance(suite, loader.suiteClass)
111+
self.assertEqual(list(suite), [])
112+
113+
# "Do not load any tests from `FunctionTestCase` class."
114+
def test_loadTestsFromTestCase__from_FunctionTestCase(self):
115+
loader = unittest.TestLoader()
116+
117+
suite = loader.loadTestsFromTestCase(unittest.FunctionTestCase)
118+
self.assertIsInstance(suite, loader.suiteClass)
119+
self.assertEqual(list(suite), [])
120+
105121
################################################################
106122
### /Tests for TestLoader.loadTestsFromTestCase
107123

@@ -123,6 +139,19 @@ def test(self):
123139
expected = [loader.suiteClass([MyTestCase('test')])]
124140
self.assertEqual(list(suite), expected)
125141

142+
# "This test ensures that internal `TestCase` subclasses are not loaded"
143+
def test_loadTestsFromModule__TestCase_subclass_internals(self):
144+
# See https://github.com/python/cpython/issues/84867
145+
m = types.ModuleType('m')
146+
# Simulate imported names:
147+
m.TestCase = unittest.TestCase
148+
m.FunctionTestCase = unittest.FunctionTestCase
149+
150+
loader = unittest.TestLoader()
151+
suite = loader.loadTestsFromModule(m)
152+
self.assertIsInstance(suite, loader.suiteClass)
153+
self.assertEqual(list(suite), [])
154+
126155
# "This method searches `module` for classes derived from TestCase"
127156
#
128157
# What happens if no tests are found (no TestCase instances)?
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:class:`unittest.TestLoader` no longer loads test cases from exact
2+
:class:`unittest.TestCase` and :class:`unittest.FunctionTestCase` classes.

0 commit comments

Comments
 (0)