Skip to content

Commit eae2b38

Browse files
committed
python#16935: unittest now counts the module as skipped if it raises SkipTest, instead of counting it as an error. Patch by Zachary Ware.
1 parent dacb685 commit eae2b38

File tree

4 files changed

+43
-5
lines changed

4 files changed

+43
-5
lines changed

Doc/library/unittest.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1493,7 +1493,9 @@ Loading and running tests
14931493
directory must be specified separately.
14941494

14951495
If importing a module fails, for example due to a syntax error, then this
1496-
will be recorded as a single error and discovery will continue.
1496+
will be recorded as a single error and discovery will continue. If the
1497+
import failure is due to ``SkipTest`` being raised, it will be recorded
1498+
as a skip instead of an error.
14971499

14981500
If a test package name (directory with :file:`__init__.py`) matches the
14991501
pattern then the package will be checked for a ``load_tests``
@@ -1512,6 +1514,10 @@ Loading and running tests
15121514

15131515
.. versionadded:: 3.2
15141516

1517+
.. versionchanged:: 3.4
1518+
Modules that raise ``SkipTest`` on import are recorded as skips, not
1519+
errors.
1520+
15151521

15161522
The following attributes of a :class:`TestLoader` can be configured either by
15171523
subclassing or assignment on an instance:

Lib/unittest/loader.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ def testFailure(self):
3434
TestClass = type(classname, (case.TestCase,), attrs)
3535
return suiteClass((TestClass(methodname),))
3636

37+
def _make_skipped_test(methodname, exception, suiteClass):
38+
@case.skip(str(exception))
39+
def testSkipped(self):
40+
pass
41+
attrs = {methodname: testSkipped}
42+
TestClass = type("ModuleSkipped", (case.TestCase,), attrs)
43+
return suiteClass((TestClass(methodname),))
44+
3745
def _jython_aware_splitext(path):
3846
if path.lower().endswith('$py.class'):
3947
return path[:-9]
@@ -259,6 +267,8 @@ def _find_tests(self, start_dir, pattern):
259267
name = self._get_name_from_path(full_path)
260268
try:
261269
module = self._get_module_from_name(name)
270+
except case.SkipTest as e:
271+
yield _make_skipped_test(name, e, self.suiteClass)
262272
except:
263273
yield _make_failed_import_test(name, self.suiteClass)
264274
else:

Lib/unittest/test/test_discovery.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,9 @@ def _find_tests(start_dir, pattern):
184184
self.assertEqual(_find_tests_args, [(start_dir, 'pattern')])
185185
self.assertIn(top_level_dir, sys.path)
186186

187-
def test_discover_with_modules_that_fail_to_import(self):
188-
loader = unittest.TestLoader()
189-
187+
def setup_import_issue_tests(self, fakefile):
190188
listdir = os.listdir
191-
os.listdir = lambda _: ['test_this_does_not_exist.py']
189+
os.listdir = lambda _: [fakefile]
192190
isfile = os.path.isfile
193191
os.path.isfile = lambda _: True
194192
orig_sys_path = sys.path[:]
@@ -198,6 +196,11 @@ def restore():
198196
sys.path[:] = orig_sys_path
199197
self.addCleanup(restore)
200198

199+
def test_discover_with_modules_that_fail_to_import(self):
200+
loader = unittest.TestLoader()
201+
202+
self.setup_import_issue_tests('test_this_does_not_exist.py')
203+
201204
suite = loader.discover('.')
202205
self.assertIn(os.getcwd(), sys.path)
203206
self.assertEqual(suite.countTestCases(), 1)
@@ -206,6 +209,22 @@ def restore():
206209
with self.assertRaises(ImportError):
207210
test.test_this_does_not_exist()
208211

212+
def test_discover_with_module_that_raises_SkipTest_on_import(self):
213+
loader = unittest.TestLoader()
214+
215+
def _get_module_from_name(name):
216+
raise unittest.SkipTest('skipperoo')
217+
loader._get_module_from_name = _get_module_from_name
218+
219+
self.setup_import_issue_tests('test_skip_dummy.py')
220+
221+
suite = loader.discover('.')
222+
self.assertEqual(suite.countTestCases(), 1)
223+
224+
result = unittest.TestResult()
225+
suite.run(result)
226+
self.assertEqual(len(result.skipped), 1)
227+
209228
def test_command_line_handling_parseArgs(self):
210229
program = TestableTestProgram()
211230

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,9 @@ Core and Builtins
270270
Library
271271
-------
272272

273+
- Issue #16935: unittest now counts the module as skipped if it raises SkipTest,
274+
instead of counting it as an error. Patch by Zachary Ware.
275+
273276
- Issue #17018: Make Process.join() retry if os.waitpid() fails with EINTR.
274277

275278
- Issue #17197: profile/cProfile modules refactored so that code of run() and

0 commit comments

Comments
 (0)