From d833779ceaebeb29352488ffddabf5fc2f070364 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Wed, 18 Mar 2015 23:56:46 +0100 Subject: Issue #22903: The fake test case created by unittest.loader when it fails importing a test module is now picklable. --- Lib/unittest/loader.py | 29 ++++++++++++++++++++--------- Lib/unittest/test/test_discovery.py | 9 +++++++++ Misc/NEWS | 3 +++ 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/Lib/unittest/loader.py b/Lib/unittest/loader.py index 808c50e..af39216 100644 --- a/Lib/unittest/loader.py +++ b/Lib/unittest/loader.py @@ -19,20 +19,31 @@ __unittest = True VALID_MODULE_NAME = re.compile(r'[_a-z]\w*\.py$', re.IGNORECASE) +class _FailedTest(case.TestCase): + _testMethodName = None + + def __init__(self, method_name, exception): + self._exception = exception + super(_FailedTest, self).__init__(method_name) + + def __getattr__(self, name): + if name != self._testMethodName: + return super(_FailedTest, self).__getattr__(name) + def testFailure(): + raise self._exception + return testFailure + + def _make_failed_import_test(name, suiteClass): message = 'Failed to import test module: %s\n%s' % (name, traceback.format_exc()) - return _make_failed_test('ModuleImportFailure', name, ImportError(message), - suiteClass) + return _make_failed_test(name, ImportError(message), suiteClass) def _make_failed_load_tests(name, exception, suiteClass): - return _make_failed_test('LoadTestsFailure', name, exception, suiteClass) + return _make_failed_test(name, exception, suiteClass) -def _make_failed_test(classname, methodname, exception, suiteClass): - def testFailure(self): - raise exception - attrs = {methodname: testFailure} - TestClass = type(classname, (case.TestCase,), attrs) - return suiteClass((TestClass(methodname),)) +def _make_failed_test(methodname, exception, suiteClass): + test = _FailedTest(methodname, exception) + return suiteClass((test,)) def _make_skipped_test(methodname, exception, suiteClass): @case.skip(str(exception)) diff --git a/Lib/unittest/test/test_discovery.py b/Lib/unittest/test/test_discovery.py index abb9066..f12e898 100644 --- a/Lib/unittest/test/test_discovery.py +++ b/Lib/unittest/test/test_discovery.py @@ -2,6 +2,7 @@ import os import re import sys import types +import pickle import builtins from test import support @@ -216,6 +217,10 @@ class TestDiscovery(unittest.TestCase): with self.assertRaises(ImportError): test.test_this_does_not_exist() + # Check picklability + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + pickle.loads(pickle.dumps(test, proto)) + def test_discover_with_module_that_raises_SkipTest_on_import(self): loader = unittest.TestLoader() @@ -232,6 +237,10 @@ class TestDiscovery(unittest.TestCase): suite.run(result) self.assertEqual(len(result.skipped), 1) + # Check picklability + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + pickle.loads(pickle.dumps(suite, proto)) + def test_command_line_handling_parseArgs(self): program = TestableTestProgram() diff --git a/Misc/NEWS b/Misc/NEWS index 90edc96..2ec41cd 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Core and Builtins Library ------- +- Issue #22903: The fake test case created by unittest.loader when it fails + importing a test module is now picklable. + - Issue #23568: Add rdivmod support to MagicMock() objects. Patch by Håkan Lövdahl. -- cgit v0.12