5 from unittest2 import case, util
11 class BaseTestSuite(unittest.TestSuite):
12 """A simple test suite that doesn't provide class or module shared fixtures.
14 def __init__(self, tests=()):
19 return "<%s tests=%s>" % (util.strclass(self.__class__), list(self))
21 def __eq__(self, other):
22 if not isinstance(other, self.__class__):
24 return list(self) == list(other)
26 def __ne__(self, other):
27 return not self == other
29 # Can't guarantee hash invariant, so flag as unhashable
33 return iter(self._tests)
35 def countTestCases(self):
38 cases += test.countTestCases()
41 def addTest(self, test):
43 if not hasattr(test, '__call__'):
44 raise TypeError("%r is not callable" % (repr(test),))
45 if isinstance(test, type) and issubclass(test,
46 (case.TestCase, TestSuite)):
47 raise TypeError("TestCases and TestSuites must be instantiated "
48 "before passing them to addTest()")
49 self._tests.append(test)
51 def addTests(self, tests):
52 if isinstance(tests, six.string_types):
53 raise TypeError("tests must be an iterable of tests, not a string")
57 def run(self, result):
64 def __call__(self, *args, **kwds):
65 return self.run(*args, **kwds)
68 """Run the tests without collecting errors in a TestResult"""
73 class TestSuite(BaseTestSuite):
74 """A test suite is a composite test consisting of a number of TestCases.
76 For use, create an instance of TestSuite, then add test case instances.
77 When all tests have been added, the suite can be passed to a test
78 runner, such as TextTestRunner. It will run the individual test cases
79 in the order in which they were added, aggregating the results. When
80 subclassing, do not forget to call the base class constructor.
84 def run(self, result):
85 self._wrapped_run(result)
86 self._tearDownPreviousClass(None, result)
87 self._handleModuleTearDown(result)
91 """Run the tests without collecting errors in a TestResult"""
92 debug = _DebugResult()
93 self._wrapped_run(debug, True)
94 self._tearDownPreviousClass(None, debug)
95 self._handleModuleTearDown(debug)
97 ################################
99 def _wrapped_run(self, result, debug=False):
101 if result.shouldStop:
104 if _isnotsuite(test):
105 self._tearDownPreviousClass(test, result)
106 self._handleModuleFixture(test, result)
107 self._handleClassSetUp(test, result)
108 result._previousTestClass = test.__class__
110 if (getattr(test.__class__, '_classSetupFailed', False) or
111 getattr(result, '_moduleSetUpFailed', False)):
114 if hasattr(test, '_wrapped_run'):
115 test._wrapped_run(result, debug)
121 def _handleClassSetUp(self, test, result):
122 previousClass = getattr(result, '_previousTestClass', None)
123 currentClass = test.__class__
124 if currentClass == previousClass:
126 if result._moduleSetUpFailed:
128 if getattr(currentClass, "__unittest_skip__", False):
132 currentClass._classSetupFailed = False
134 # test may actually be a function
135 # so its class will be a builtin-type
138 setUpClass = getattr(currentClass, 'setUpClass', None)
139 if setUpClass is not None:
142 except Exception as e:
143 if isinstance(result, _DebugResult):
145 currentClass._classSetupFailed = True
146 className = util.strclass(currentClass)
147 errorName = 'setUpClass (%s)' % className
148 self._addClassOrModuleLevelException(result, e, errorName)
150 def _get_previous_module(self, result):
151 previousModule = None
152 previousClass = getattr(result, '_previousTestClass', None)
153 if previousClass is not None:
154 previousModule = previousClass.__module__
155 return previousModule
158 def _handleModuleFixture(self, test, result):
159 previousModule = self._get_previous_module(result)
160 currentModule = test.__class__.__module__
161 if currentModule == previousModule:
164 self._handleModuleTearDown(result)
167 result._moduleSetUpFailed = False
169 module = sys.modules[currentModule]
172 setUpModule = getattr(module, 'setUpModule', None)
173 if setUpModule is not None:
176 except Exception as e:
177 if isinstance(result, _DebugResult):
179 result._moduleSetUpFailed = True
180 errorName = 'setUpModule (%s)' % currentModule
181 self._addClassOrModuleLevelException(result, e, errorName)
183 def _addClassOrModuleLevelException(self, result, exception, errorName):
184 error = _ErrorHolder(errorName)
185 addSkip = getattr(result, 'addSkip', None)
186 if addSkip is not None and isinstance(exception, case.SkipTest):
187 addSkip(error, str(exception))
189 result.addError(error, sys.exc_info())
191 def _handleModuleTearDown(self, result):
192 previousModule = self._get_previous_module(result)
193 if previousModule is None:
195 if result._moduleSetUpFailed:
199 module = sys.modules[previousModule]
203 tearDownModule = getattr(module, 'tearDownModule', None)
204 if tearDownModule is not None:
207 except Exception as e:
208 if isinstance(result, _DebugResult):
210 errorName = 'tearDownModule (%s)' % previousModule
211 self._addClassOrModuleLevelException(result, e, errorName)
213 def _tearDownPreviousClass(self, test, result):
214 previousClass = getattr(result, '_previousTestClass', None)
215 currentClass = test.__class__
216 if currentClass == previousClass:
218 if getattr(previousClass, '_classSetupFailed', False):
220 if getattr(result, '_moduleSetUpFailed', False):
222 if getattr(previousClass, "__unittest_skip__", False):
225 tearDownClass = getattr(previousClass, 'tearDownClass', None)
226 if tearDownClass is not None:
229 except Exception as e:
230 if isinstance(result, _DebugResult):
232 className = util.strclass(previousClass)
233 errorName = 'tearDownClass (%s)' % className
234 self._addClassOrModuleLevelException(result, e, errorName)
237 class _ErrorHolder(object):
239 Placeholder for a TestCase inside a result. As far as a TestResult
240 is concerned, this looks exactly like a unit test. Used to insert
241 arbitrary errors into a test suite run.
243 # Inspired by the ErrorHolder from Twisted:
244 # http://twistedmatrix.com/trac/browser/trunk/twisted/trial/runner.py
246 # attribute used by TestResult._exc_info_to_string
247 failureException = None
249 def __init__(self, description):
250 self.description = description
253 return self.description
255 def shortDescription(self):
259 return "<ErrorHolder description=%r>" % (self.description,)
264 def run(self, result):
265 # could call result.addError(...) - but this test-like object
266 # shouldn't be run anyway
269 def __call__(self, result):
270 return self.run(result)
272 def countTestCases(self):
275 def _isnotsuite(test):
276 "A crude way to tell apart testcases and suites with duck-typing"
284 class _DebugResult(object):
285 "Used by the TestSuite to hold previous class when running in debug."
286 _previousTestClass = None
287 _moduleSetUpFailed = False