diff -r aa15df77e58f Doc/library/unittest.rst --- a/Doc/library/unittest.rst Mon Feb 11 10:05:34 2013 -0500 +++ b/Doc/library/unittest.rst Mon Feb 11 10:51:10 2013 -0600 @@ -1493,7 +1493,9 @@ directory must be specified separately. If importing a module fails, for example due to a syntax error, then this - will be recorded as a single error and discovery will continue. + will be recorded as a single error and discovery will continue. If the + import failure is due to ``SkipTest`` being raised, it will be recorded + as a skip instead of an error. If a test package name (directory with :file:`__init__.py`) matches the pattern then the package will be checked for a ``load_tests`` @@ -1512,6 +1514,10 @@ .. versionadded:: 3.2 + .. versionchanged:: 3.4 + Modules that raise ``SkipTest`` on import are recorded as skips, not + errors. + The following attributes of a :class:`TestLoader` can be configured either by subclassing or assignment on an instance: diff -r aa15df77e58f Lib/unittest/loader.py --- a/Lib/unittest/loader.py Mon Feb 11 10:05:34 2013 -0500 +++ b/Lib/unittest/loader.py Mon Feb 11 10:51:10 2013 -0600 @@ -34,6 +34,14 @@ TestClass = type(classname, (case.TestCase,), attrs) return suiteClass((TestClass(methodname),)) +def _make_skipped_test(methodname, exception, suiteClass): + @case.skip(str(exception)) + def testSkipped(self): + pass + attrs = {methodname: testSkipped} + TestClass = type("ModuleSkipped", (case.TestCase,), attrs) + return suiteClass((TestClass(methodname),)) + def _jython_aware_splitext(path): if path.lower().endswith('$py.class'): return path[:-9] @@ -259,6 +267,8 @@ name = self._get_name_from_path(full_path) try: module = self._get_module_from_name(name) + except case.SkipTest as e: + yield _make_skipped_test(name, e, self.suiteClass) except: yield _make_failed_import_test(name, self.suiteClass) else: diff -r aa15df77e58f Lib/unittest/test/test_discovery.py --- a/Lib/unittest/test/test_discovery.py Mon Feb 11 10:05:34 2013 -0500 +++ b/Lib/unittest/test/test_discovery.py Mon Feb 11 10:51:10 2013 -0600 @@ -206,6 +206,32 @@ with self.assertRaises(ImportError): test.test_this_does_not_exist() + def test_discover_with_module_that_raises_SkipTest_on_import(self): + loader = unittest.TestLoader() + + def _get_module_from_name(name): + raise unittest.SkipTest('skipperoo') + loader._get_module_from_name = _get_module_from_name + + listdir = os.listdir + os.listdir = lambda _: ['test_skip_dummy.py'] + isfile = os.path.isfile + os.path.isfile = lambda _: True + orig_sys_path = sys.path[:] + def restore(): + os.path.isfile = isfile + os.listdir = listdir + sys.path[:] = orig_sys_path + self.addCleanup(restore) + + suite = loader.discover('.') + self.assertEqual(suite.countTestCases(), 1) + test = list(list(suite)[0])[0] + + with self.assertRaises(unittest.SkipTest): + test.test_skip_dummy() + + def test_command_line_handling_parseArgs(self): program = TestableTestProgram()