blob: 8341b885af7e53e87c7af34d78776569b30bc5a6 [file] [log] [blame]
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00001"""Test case implementation"""
2
3import sys
4import functools
5import difflib
6import pprint
7import re
8import warnings
9
Michael Foord225a0992010-02-18 20:30:09 +000010from . import result
Michael Foord98e7b762010-03-20 03:00:34 +000011from .util import (
12 strclass, safe_repr, sorted_list_difference, unorderable_list_difference
13)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000014
Michael Foordb1aa30f2010-03-22 00:06:30 +000015__unittest = True
Michael Foordb1aa30f2010-03-22 00:06:30 +000016
Michael Foord5fe21ff2010-06-05 13:38:16 +000017
18DIFF_OMITTED = ('\nDiff is %s characters long. '
19 'Set self.maxDiff to None to see it.')
20
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000021class SkipTest(Exception):
22 """
23 Raise this exception in a test to skip it.
24
25 Usually you can use TestResult.skip() or one of the skipping decorators
26 instead of raising this directly.
27 """
28 pass
29
30class _ExpectedFailure(Exception):
31 """
32 Raise this when a test is expected to fail.
33
34 This is an implementation detail.
35 """
36
37 def __init__(self, exc_info):
38 super(_ExpectedFailure, self).__init__()
39 self.exc_info = exc_info
40
41class _UnexpectedSuccess(Exception):
42 """
43 The test was supposed to fail, but it didn't!
44 """
45 pass
46
47def _id(obj):
48 return obj
49
50def skip(reason):
51 """
52 Unconditionally skip a test.
53 """
54 def decorator(test_item):
Michael Foord53e8eea2010-03-07 20:22:12 +000055 if not (isinstance(test_item, type) and issubclass(test_item, TestCase)):
56 @functools.wraps(test_item)
57 def skip_wrapper(*args, **kwargs):
58 raise SkipTest(reason)
59 test_item = skip_wrapper
60
61 test_item.__unittest_skip__ = True
62 test_item.__unittest_skip_why__ = reason
63 return test_item
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +000064 return decorator
65
66def skipIf(condition, reason):
67 """
68 Skip a test if the condition is true.
69 """
70 if condition:
71 return skip(reason)
72 return _id
73
74def skipUnless(condition, reason):
75 """
76 Skip a test unless the condition is true.
77 """
78 if not condition:
79 return skip(reason)
80 return _id
81
82
83def expectedFailure(func):
84 @functools.wraps(func)
85 def wrapper(*args, **kwargs):
86 try:
87 func(*args, **kwargs)
88 except Exception:
89 raise _ExpectedFailure(sys.exc_info())
90 raise _UnexpectedSuccess
91 return wrapper
92
93
94class _AssertRaisesContext(object):
95 """A context manager used to implement TestCase.assertRaises* methods."""
96
97 def __init__(self, expected, test_case, expected_regexp=None):
98 self.expected = expected
99 self.failureException = test_case.failureException
Georg Brandlb0eb4d32010-02-07 11:34:15 +0000100 self.expected_regexp = expected_regexp
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000101
102 def __enter__(self):
Michael Foord2bd52dc2010-02-07 18:44:12 +0000103 return self
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000104
105 def __exit__(self, exc_type, exc_value, tb):
106 if exc_type is None:
107 try:
108 exc_name = self.expected.__name__
109 except AttributeError:
110 exc_name = str(self.expected)
111 raise self.failureException(
112 "{0} not raised".format(exc_name))
113 if not issubclass(exc_type, self.expected):
114 # let unexpected exceptions pass through
115 return False
Georg Brandldc3694b2010-02-07 17:02:22 +0000116 self.exception = exc_value # store for later retrieval
Georg Brandlb0eb4d32010-02-07 11:34:15 +0000117 if self.expected_regexp is None:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000118 return True
119
Georg Brandlb0eb4d32010-02-07 11:34:15 +0000120 expected_regexp = self.expected_regexp
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000121 if isinstance(expected_regexp, basestring):
122 expected_regexp = re.compile(expected_regexp)
123 if not expected_regexp.search(str(exc_value)):
124 raise self.failureException('"%s" does not match "%s"' %
125 (expected_regexp.pattern, str(exc_value)))
126 return True
127
128
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000129class TestCase(object):
130 """A class whose instances are single test cases.
131
132 By default, the test code itself should be placed in a method named
133 'runTest'.
134
135 If the fixture may be used for many test cases, create as
136 many test methods as are needed. When instantiating such a TestCase
137 subclass, specify in the constructor arguments the name of the test method
138 that the instance is to execute.
139
140 Test authors should subclass TestCase for their own tests. Construction
141 and deconstruction of the test's environment ('fixture') can be
142 implemented by overriding the 'setUp' and 'tearDown' methods respectively.
143
144 If it is necessary to override the __init__ method, the base class
145 __init__ method must always be called. It is important that subclasses
146 should not change the signature of their __init__ method, since instances
147 of the classes are instantiated automatically by parts of the framework
148 in order to be run.
149 """
150
151 # This attribute determines which exception will be raised when
152 # the instance's assertion methods fail; test methods raising this
153 # exception will be deemed to have 'failed' rather than 'errored'
154
155 failureException = AssertionError
156
157 # This attribute determines whether long messages (including repr of
158 # objects used in assert methods) will be printed on failure in *addition*
159 # to any explicit message passed.
160
161 longMessage = False
162
Michael Foorde37d75f2010-06-05 12:10:52 +0000163 # This attribute sets the maximum length of a diff in failure messsages
164 # by assert methods using difflib. It is looked up as an instance attribute
165 # so can be configured by individual tests if required.
Michael Foordc532c572010-06-05 23:58:40 +0000166
Michael Foorde37d75f2010-06-05 12:10:52 +0000167 maxDiff = 80*8
168
Michael Foord5ffa3252010-03-07 22:04:55 +0000169 # Attribute used by TestSuite for classSetUp
170
171 _classSetupFailed = False
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000172
173 def __init__(self, methodName='runTest'):
174 """Create an instance of the class that will use the named test
175 method when executed. Raises a ValueError if the instance does
176 not have a method with the specified name.
177 """
178 self._testMethodName = methodName
179 self._resultForDoCleanups = None
180 try:
181 testMethod = getattr(self, methodName)
182 except AttributeError:
Michael Foordc2294dd2010-02-18 21:37:07 +0000183 raise ValueError("no such test method in %s: %s" %
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000184 (self.__class__, methodName))
185 self._testMethodDoc = testMethod.__doc__
186 self._cleanups = []
187
188 # Map types to custom assertEqual functions that will compare
189 # instances of said type in more detail to generate a more useful
190 # error message.
191 self._type_equality_funcs = {}
192 self.addTypeEqualityFunc(dict, self.assertDictEqual)
193 self.addTypeEqualityFunc(list, self.assertListEqual)
194 self.addTypeEqualityFunc(tuple, self.assertTupleEqual)
195 self.addTypeEqualityFunc(set, self.assertSetEqual)
196 self.addTypeEqualityFunc(frozenset, self.assertSetEqual)
Michael Foordfe6349c2010-02-08 22:41:16 +0000197 self.addTypeEqualityFunc(unicode, self.assertMultiLineEqual)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000198
199 def addTypeEqualityFunc(self, typeobj, function):
200 """Add a type specific assertEqual style function to compare a type.
201
202 This method is for use by TestCase subclasses that need to register
203 their own type equality functions to provide nicer error messages.
204
205 Args:
206 typeobj: The data type to call this function on when both values
207 are of the same type in assertEqual().
208 function: The callable taking two arguments and an optional
209 msg= argument that raises self.failureException with a
210 useful error message when the two arguments are not equal.
211 """
Benjamin Petersond46430b2009-11-29 22:26:26 +0000212 self._type_equality_funcs[typeobj] = function
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000213
214 def addCleanup(self, function, *args, **kwargs):
215 """Add a function, with arguments, to be called when the test is
216 completed. Functions added are called on a LIFO basis and are
217 called after tearDown on test failure or success.
218
219 Cleanup items are called even if setUp fails (unlike tearDown)."""
220 self._cleanups.append((function, args, kwargs))
221
222 def setUp(self):
223 "Hook method for setting up the test fixture before exercising it."
224 pass
225
226 def tearDown(self):
227 "Hook method for deconstructing the test fixture after testing it."
228 pass
229
Michael Foord5ffa3252010-03-07 22:04:55 +0000230 @classmethod
231 def setUpClass(cls):
232 "Hook method for setting up class fixture before running tests in the class."
233
234 @classmethod
235 def tearDownClass(cls):
236 "Hook method for deconstructing the class fixture after running all tests in the class."
237
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000238 def countTestCases(self):
239 return 1
240
241 def defaultTestResult(self):
242 return result.TestResult()
243
244 def shortDescription(self):
Michael Foorddb43b5a2010-02-10 14:25:12 +0000245 """Returns a one-line description of the test, or None if no
246 description has been provided.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000247
Michael Foorddb43b5a2010-02-10 14:25:12 +0000248 The default implementation of this method returns the first line of
249 the specified test method's docstring.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000250 """
Michael Foorddb43b5a2010-02-10 14:25:12 +0000251 doc = self._testMethodDoc
252 return doc and doc.split("\n")[0].strip() or None
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000253
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000254
255 def id(self):
Michael Foord225a0992010-02-18 20:30:09 +0000256 return "%s.%s" % (strclass(self.__class__), self._testMethodName)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000257
258 def __eq__(self, other):
259 if type(self) is not type(other):
260 return NotImplemented
261
262 return self._testMethodName == other._testMethodName
263
264 def __ne__(self, other):
265 return not self == other
266
267 def __hash__(self):
268 return hash((type(self), self._testMethodName))
269
270 def __str__(self):
Michael Foord225a0992010-02-18 20:30:09 +0000271 return "%s (%s)" % (self._testMethodName, strclass(self.__class__))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000272
273 def __repr__(self):
274 return "<%s testMethod=%s>" % \
Michael Foord225a0992010-02-18 20:30:09 +0000275 (strclass(self.__class__), self._testMethodName)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000276
Michael Foordae3db0a2010-02-22 23:28:32 +0000277 def _addSkip(self, result, reason):
278 addSkip = getattr(result, 'addSkip', None)
279 if addSkip is not None:
280 addSkip(self, reason)
281 else:
282 warnings.warn("TestResult has no addSkip method, skips not reported",
283 RuntimeWarning, 2)
284 result.addSuccess(self)
285
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000286 def run(self, result=None):
287 orig_result = result
288 if result is None:
289 result = self.defaultTestResult()
290 startTestRun = getattr(result, 'startTestRun', None)
291 if startTestRun is not None:
292 startTestRun()
293
294 self._resultForDoCleanups = result
295 result.startTest(self)
Michael Foord53e8eea2010-03-07 20:22:12 +0000296
297 testMethod = getattr(self, self._testMethodName)
298 if (getattr(self.__class__, "__unittest_skip__", False) or
299 getattr(testMethod, "__unittest_skip__", False)):
300 # If the class or method was skipped.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000301 try:
Michael Foord53e8eea2010-03-07 20:22:12 +0000302 skip_why = (getattr(self.__class__, '__unittest_skip_why__', '')
303 or getattr(testMethod, '__unittest_skip_why__', ''))
304 self._addSkip(result, skip_why)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000305 finally:
306 result.stopTest(self)
307 return
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000308 try:
309 success = False
310 try:
311 self.setUp()
312 except SkipTest as e:
Michael Foordae3db0a2010-02-22 23:28:32 +0000313 self._addSkip(result, str(e))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000314 except Exception:
315 result.addError(self, sys.exc_info())
316 else:
317 try:
318 testMethod()
319 except self.failureException:
320 result.addFailure(self, sys.exc_info())
321 except _ExpectedFailure as e:
Michael Foordae3db0a2010-02-22 23:28:32 +0000322 addExpectedFailure = getattr(result, 'addExpectedFailure', None)
323 if addExpectedFailure is not None:
324 addExpectedFailure(self, e.exc_info)
325 else:
326 warnings.warn("TestResult has no addExpectedFailure method, reporting as passes",
327 RuntimeWarning)
328 result.addSuccess(self)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000329 except _UnexpectedSuccess:
Michael Foordae3db0a2010-02-22 23:28:32 +0000330 addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None)
331 if addUnexpectedSuccess is not None:
332 addUnexpectedSuccess(self)
333 else:
334 warnings.warn("TestResult has no addUnexpectedSuccess method, reporting as failures",
335 RuntimeWarning)
336 result.addFailure(self, sys.exc_info())
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000337 except SkipTest as e:
Michael Foordae3db0a2010-02-22 23:28:32 +0000338 self._addSkip(result, str(e))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000339 except Exception:
340 result.addError(self, sys.exc_info())
341 else:
342 success = True
343
344 try:
345 self.tearDown()
346 except Exception:
347 result.addError(self, sys.exc_info())
348 success = False
349
350 cleanUpSuccess = self.doCleanups()
351 success = success and cleanUpSuccess
352 if success:
353 result.addSuccess(self)
354 finally:
355 result.stopTest(self)
356 if orig_result is None:
357 stopTestRun = getattr(result, 'stopTestRun', None)
358 if stopTestRun is not None:
359 stopTestRun()
360
361 def doCleanups(self):
362 """Execute all cleanup functions. Normally called for you after
363 tearDown."""
364 result = self._resultForDoCleanups
365 ok = True
366 while self._cleanups:
367 function, args, kwargs = self._cleanups.pop(-1)
368 try:
369 function(*args, **kwargs)
370 except Exception:
371 ok = False
372 result.addError(self, sys.exc_info())
373 return ok
374
375 def __call__(self, *args, **kwds):
376 return self.run(*args, **kwds)
377
378 def debug(self):
379 """Run the test without collecting errors in a TestResult"""
380 self.setUp()
381 getattr(self, self._testMethodName)()
382 self.tearDown()
383
384 def skipTest(self, reason):
385 """Skip this test."""
386 raise SkipTest(reason)
387
388 def fail(self, msg=None):
389 """Fail immediately, with the given message."""
390 raise self.failureException(msg)
391
392 def assertFalse(self, expr, msg=None):
393 "Fail the test if the expression is true."
394 if expr:
Michael Foord225a0992010-02-18 20:30:09 +0000395 msg = self._formatMessage(msg, "%s is not False" % safe_repr(expr))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000396 raise self.failureException(msg)
397
398 def assertTrue(self, expr, msg=None):
399 """Fail the test unless the expression is true."""
400 if not expr:
Michael Foord225a0992010-02-18 20:30:09 +0000401 msg = self._formatMessage(msg, "%s is not True" % safe_repr(expr))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000402 raise self.failureException(msg)
403
404 def _formatMessage(self, msg, standardMsg):
405 """Honour the longMessage attribute when generating failure messages.
406 If longMessage is False this means:
407 * Use only an explicit message if it is provided
408 * Otherwise use the standard message for the assert
409
410 If longMessage is True:
411 * Use the standard message
412 * If an explicit message is provided, plus ' : ' and the explicit message
413 """
414 if not self.longMessage:
415 return msg or standardMsg
416 if msg is None:
417 return standardMsg
Michael Foord53e8eea2010-03-07 20:22:12 +0000418 try:
419 # don't switch to '{}' formatting in Python 2.X
420 # it changes the way unicode input is handled
421 return '%s : %s' % (standardMsg, msg)
422 except UnicodeDecodeError:
423 return '%s : %s' % (safe_repr(standardMsg), safe_repr(msg))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000424
425
426 def assertRaises(self, excClass, callableObj=None, *args, **kwargs):
427 """Fail unless an exception of class excClass is thrown
428 by callableObj when invoked with arguments args and keyword
429 arguments kwargs. If a different type of exception is
430 thrown, it will not be caught, and the test case will be
431 deemed to have suffered an error, exactly as for an
432 unexpected exception.
433
434 If called with callableObj omitted or None, will return a
435 context object used like this::
436
Michael Foordd0edec32010-02-05 22:55:09 +0000437 with self.assertRaises(SomeException):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000438 do_something()
Michael Foordd0edec32010-02-05 22:55:09 +0000439
440 The context manager keeps a reference to the exception as
Ezio Melotticd4f6572010-02-08 21:52:08 +0000441 the 'exception' attribute. This allows you to inspect the
Michael Foordd0edec32010-02-05 22:55:09 +0000442 exception after the assertion::
443
444 with self.assertRaises(SomeException) as cm:
445 do_something()
Georg Brandldc3694b2010-02-07 17:02:22 +0000446 the_exception = cm.exception
Michael Foord757cc4d2010-02-05 23:22:37 +0000447 self.assertEqual(the_exception.error_code, 3)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000448 """
449 context = _AssertRaisesContext(excClass, self)
450 if callableObj is None:
451 return context
452 with context:
453 callableObj(*args, **kwargs)
454
455 def _getAssertEqualityFunc(self, first, second):
456 """Get a detailed comparison function for the types of the two args.
457
458 Returns: A callable accepting (first, second, msg=None) that will
459 raise a failure exception if first != second with a useful human
460 readable error message for those types.
461 """
462 #
463 # NOTE(gregory.p.smith): I considered isinstance(first, type(second))
464 # and vice versa. I opted for the conservative approach in case
465 # subclasses are not intended to be compared in detail to their super
466 # class instances using a type equality func. This means testing
467 # subtypes won't automagically use the detailed comparison. Callers
468 # should use their type specific assertSpamEqual method to compare
469 # subclasses if the detailed comparison is desired and appropriate.
470 # See the discussion in http://bugs.python.org/issue2578.
471 #
472 if type(first) is type(second):
473 asserter = self._type_equality_funcs.get(type(first))
474 if asserter is not None:
Benjamin Petersond46430b2009-11-29 22:26:26 +0000475 return asserter
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000476
477 return self._baseAssertEqual
478
479 def _baseAssertEqual(self, first, second, msg=None):
480 """The default assertEqual implementation, not type specific."""
481 if not first == second:
Michael Foord225a0992010-02-18 20:30:09 +0000482 standardMsg = '%s != %s' % (safe_repr(first), safe_repr(second))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000483 msg = self._formatMessage(msg, standardMsg)
484 raise self.failureException(msg)
485
486 def assertEqual(self, first, second, msg=None):
487 """Fail if the two objects are unequal as determined by the '=='
488 operator.
489 """
490 assertion_func = self._getAssertEqualityFunc(first, second)
491 assertion_func(first, second, msg=msg)
492
493 def assertNotEqual(self, first, second, msg=None):
494 """Fail if the two objects are equal as determined by the '=='
495 operator.
496 """
497 if not first != second:
Michael Foord225a0992010-02-18 20:30:09 +0000498 msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first),
499 safe_repr(second)))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000500 raise self.failureException(msg)
501
Michael Foorda7e08fe2010-03-27 19:10:11 +0000502
503 def assertAlmostEqual(self, first, second, places=None, msg=None, delta=None):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000504 """Fail if the two objects are unequal as determined by their
505 difference rounded to the given number of decimal places
Michael Foorda7e08fe2010-03-27 19:10:11 +0000506 (default 7) and comparing to zero, or by comparing that the
507 between the two objects is more than the given delta.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000508
509 Note that decimal places (from zero) are usually not the same
510 as significant digits (measured from the most signficant digit).
Michael Foordc3f79372009-09-13 16:40:02 +0000511
512 If the two objects compare equal then they will automatically
513 compare almost equal.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000514 """
Michael Foordc3f79372009-09-13 16:40:02 +0000515 if first == second:
Michael Foorda7e08fe2010-03-27 19:10:11 +0000516 # shortcut
Michael Foordc3f79372009-09-13 16:40:02 +0000517 return
Michael Foorda7e08fe2010-03-27 19:10:11 +0000518 if delta is not None and places is not None:
519 raise TypeError("specify delta or places not both")
520
521 if delta is not None:
522 if abs(first - second) <= delta:
523 return
524
525 standardMsg = '%s != %s within %s delta' % (safe_repr(first),
526 safe_repr(second),
527 safe_repr(delta))
528 else:
529 if places is None:
530 places = 7
531
532 if round(abs(second-first), places) == 0:
533 return
534
Michael Foord225a0992010-02-18 20:30:09 +0000535 standardMsg = '%s != %s within %r places' % (safe_repr(first),
536 safe_repr(second),
537 places)
Michael Foorda7e08fe2010-03-27 19:10:11 +0000538 msg = self._formatMessage(msg, standardMsg)
539 raise self.failureException(msg)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000540
Michael Foorda7e08fe2010-03-27 19:10:11 +0000541 def assertNotAlmostEqual(self, first, second, places=None, msg=None, delta=None):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000542 """Fail if the two objects are equal as determined by their
543 difference rounded to the given number of decimal places
Michael Foorda7e08fe2010-03-27 19:10:11 +0000544 (default 7) and comparing to zero, or by comparing that the
545 between the two objects is less than the given delta.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000546
547 Note that decimal places (from zero) are usually not the same
548 as significant digits (measured from the most signficant digit).
Michael Foordc3f79372009-09-13 16:40:02 +0000549
550 Objects that are equal automatically fail.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000551 """
Michael Foorda7e08fe2010-03-27 19:10:11 +0000552 if delta is not None and places is not None:
553 raise TypeError("specify delta or places not both")
554 if delta is not None:
555 if not (first == second) and abs(first - second) > delta:
556 return
557 standardMsg = '%s == %s within %s delta' % (safe_repr(first),
558 safe_repr(second),
559 safe_repr(delta))
560 else:
561 if places is None:
562 places = 7
563 if not (first == second) and round(abs(second-first), places) != 0:
564 return
Michael Foord225a0992010-02-18 20:30:09 +0000565 standardMsg = '%s == %s within %r places' % (safe_repr(first),
Michael Foorda7e08fe2010-03-27 19:10:11 +0000566 safe_repr(second),
567 places)
568
569 msg = self._formatMessage(msg, standardMsg)
570 raise self.failureException(msg)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000571
572 # Synonyms for assertion methods
573
574 # The plurals are undocumented. Keep them that way to discourage use.
575 # Do not add more. Do not remove.
576 # Going through a deprecation cycle on these would annoy many people.
577 assertEquals = assertEqual
578 assertNotEquals = assertNotEqual
579 assertAlmostEquals = assertAlmostEqual
580 assertNotAlmostEquals = assertNotAlmostEqual
Michael Foord67dfc772010-02-10 14:31:30 +0000581 assert_ = assertTrue
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000582
583 # These fail* assertion method names are pending deprecation and will
584 # be a DeprecationWarning in 3.2; http://bugs.python.org/issue2578
585 def _deprecate(original_func):
586 def deprecated_func(*args, **kwargs):
587 warnings.warn(
588 'Please use {0} instead.'.format(original_func.__name__),
589 PendingDeprecationWarning, 2)
590 return original_func(*args, **kwargs)
591 return deprecated_func
592
593 failUnlessEqual = _deprecate(assertEqual)
594 failIfEqual = _deprecate(assertNotEqual)
595 failUnlessAlmostEqual = _deprecate(assertAlmostEqual)
596 failIfAlmostEqual = _deprecate(assertNotAlmostEqual)
597 failUnless = _deprecate(assertTrue)
598 failUnlessRaises = _deprecate(assertRaises)
599 failIf = _deprecate(assertFalse)
600
Michael Foorde37d75f2010-06-05 12:10:52 +0000601 def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000602 """An equality assertion for ordered sequences (like lists and tuples).
603
R. David Murray05b41712010-01-29 19:35:39 +0000604 For the purposes of this function, a valid ordered sequence type is one
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000605 which can be indexed, has a length, and has an equality operator.
606
607 Args:
608 seq1: The first sequence to compare.
609 seq2: The second sequence to compare.
610 seq_type: The expected datatype of the sequences, or None if no
611 datatype should be enforced.
612 msg: Optional message to use on failure instead of a list of
613 differences.
614 """
Florent Xicluna4a0f8b82010-03-21 10:50:44 +0000615 if seq_type is not None:
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000616 seq_type_name = seq_type.__name__
617 if not isinstance(seq1, seq_type):
Michael Foord225a0992010-02-18 20:30:09 +0000618 raise self.failureException('First sequence is not a %s: %s'
619 % (seq_type_name, safe_repr(seq1)))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000620 if not isinstance(seq2, seq_type):
Michael Foord225a0992010-02-18 20:30:09 +0000621 raise self.failureException('Second sequence is not a %s: %s'
622 % (seq_type_name, safe_repr(seq2)))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000623 else:
624 seq_type_name = "sequence"
625
626 differing = None
627 try:
628 len1 = len(seq1)
629 except (TypeError, NotImplementedError):
630 differing = 'First %s has no length. Non-sequence?' % (
631 seq_type_name)
632
633 if differing is None:
634 try:
635 len2 = len(seq2)
636 except (TypeError, NotImplementedError):
637 differing = 'Second %s has no length. Non-sequence?' % (
638 seq_type_name)
639
640 if differing is None:
641 if seq1 == seq2:
642 return
643
Michael Foord225a0992010-02-18 20:30:09 +0000644 seq1_repr = safe_repr(seq1)
645 seq2_repr = safe_repr(seq2)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000646 if len(seq1_repr) > 30:
647 seq1_repr = seq1_repr[:30] + '...'
648 if len(seq2_repr) > 30:
649 seq2_repr = seq2_repr[:30] + '...'
650 elements = (seq_type_name.capitalize(), seq1_repr, seq2_repr)
651 differing = '%ss differ: %s != %s\n' % elements
652
653 for i in xrange(min(len1, len2)):
654 try:
655 item1 = seq1[i]
656 except (TypeError, IndexError, NotImplementedError):
657 differing += ('\nUnable to index element %d of first %s\n' %
658 (i, seq_type_name))
659 break
660
661 try:
662 item2 = seq2[i]
663 except (TypeError, IndexError, NotImplementedError):
664 differing += ('\nUnable to index element %d of second %s\n' %
665 (i, seq_type_name))
666 break
667
668 if item1 != item2:
669 differing += ('\nFirst differing element %d:\n%s\n%s\n' %
670 (i, item1, item2))
671 break
672 else:
673 if (len1 == len2 and seq_type is None and
674 type(seq1) != type(seq2)):
675 # The sequences are the same, but have differing types.
676 return
677
678 if len1 > len2:
679 differing += ('\nFirst %s contains %d additional '
680 'elements.\n' % (seq_type_name, len1 - len2))
681 try:
682 differing += ('First extra element %d:\n%s\n' %
683 (len2, seq1[len2]))
684 except (TypeError, IndexError, NotImplementedError):
685 differing += ('Unable to index element %d '
686 'of first %s\n' % (len2, seq_type_name))
687 elif len1 < len2:
688 differing += ('\nSecond %s contains %d additional '
689 'elements.\n' % (seq_type_name, len2 - len1))
690 try:
691 differing += ('First extra element %d:\n%s\n' %
692 (len1, seq2[len1]))
693 except (TypeError, IndexError, NotImplementedError):
694 differing += ('Unable to index element %d '
695 'of second %s\n' % (len1, seq_type_name))
Michael Foord01007022010-06-05 11:23:51 +0000696 standardMsg = differing
697 diffMsg = '\n' + '\n'.join(
Georg Brandl46cc46a2009-10-01 20:11:14 +0000698 difflib.ndiff(pprint.pformat(seq1).splitlines(),
699 pprint.pformat(seq2).splitlines()))
Michael Foorde37d75f2010-06-05 12:10:52 +0000700 standardMsg = self._truncateMessage(standardMsg, diffMsg)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000701 msg = self._formatMessage(msg, standardMsg)
702 self.fail(msg)
703
Michael Foorde37d75f2010-06-05 12:10:52 +0000704 def _truncateMessage(self, message, diff):
705 max_diff = self.maxDiff
Michael Foorda4412872010-06-05 11:46:59 +0000706 if max_diff is None or len(diff) <= max_diff:
707 return message + diff
Michael Foord5fe21ff2010-06-05 13:38:16 +0000708 return message + (DIFF_OMITTED % len(diff))
Michael Foorda4412872010-06-05 11:46:59 +0000709
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000710 def assertListEqual(self, list1, list2, msg=None):
711 """A list-specific equality assertion.
712
713 Args:
714 list1: The first list to compare.
715 list2: The second list to compare.
716 msg: Optional message to use on failure instead of a list of
717 differences.
718
719 """
720 self.assertSequenceEqual(list1, list2, msg, seq_type=list)
721
722 def assertTupleEqual(self, tuple1, tuple2, msg=None):
723 """A tuple-specific equality assertion.
724
725 Args:
726 tuple1: The first tuple to compare.
727 tuple2: The second tuple to compare.
728 msg: Optional message to use on failure instead of a list of
729 differences.
730 """
731 self.assertSequenceEqual(tuple1, tuple2, msg, seq_type=tuple)
732
733 def assertSetEqual(self, set1, set2, msg=None):
734 """A set-specific equality assertion.
735
736 Args:
737 set1: The first set to compare.
738 set2: The second set to compare.
739 msg: Optional message to use on failure instead of a list of
740 differences.
741
Michael Foord98e7b762010-03-20 03:00:34 +0000742 assertSetEqual uses ducktyping to support different types of sets, and
743 is optimized for sets specifically (parameters must support a
744 difference method).
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000745 """
746 try:
747 difference1 = set1.difference(set2)
748 except TypeError, e:
749 self.fail('invalid type when attempting set difference: %s' % e)
750 except AttributeError, e:
751 self.fail('first argument does not support set difference: %s' % e)
752
753 try:
754 difference2 = set2.difference(set1)
755 except TypeError, e:
756 self.fail('invalid type when attempting set difference: %s' % e)
757 except AttributeError, e:
758 self.fail('second argument does not support set difference: %s' % e)
759
760 if not (difference1 or difference2):
761 return
762
763 lines = []
764 if difference1:
765 lines.append('Items in the first set but not the second:')
766 for item in difference1:
767 lines.append(repr(item))
768 if difference2:
769 lines.append('Items in the second set but not the first:')
770 for item in difference2:
771 lines.append(repr(item))
772
773 standardMsg = '\n'.join(lines)
774 self.fail(self._formatMessage(msg, standardMsg))
775
776 def assertIn(self, member, container, msg=None):
777 """Just like self.assertTrue(a in b), but with a nicer default message."""
778 if member not in container:
Michael Foord225a0992010-02-18 20:30:09 +0000779 standardMsg = '%s not found in %s' % (safe_repr(member),
780 safe_repr(container))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000781 self.fail(self._formatMessage(msg, standardMsg))
782
783 def assertNotIn(self, member, container, msg=None):
784 """Just like self.assertTrue(a not in b), but with a nicer default message."""
785 if member in container:
Michael Foord225a0992010-02-18 20:30:09 +0000786 standardMsg = '%s unexpectedly found in %s' % (safe_repr(member),
787 safe_repr(container))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000788 self.fail(self._formatMessage(msg, standardMsg))
789
790 def assertIs(self, expr1, expr2, msg=None):
791 """Just like self.assertTrue(a is b), but with a nicer default message."""
792 if expr1 is not expr2:
Michael Foord225a0992010-02-18 20:30:09 +0000793 standardMsg = '%s is not %s' % (safe_repr(expr1),
Michael Foordc2294dd2010-02-18 21:37:07 +0000794 safe_repr(expr2))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000795 self.fail(self._formatMessage(msg, standardMsg))
796
797 def assertIsNot(self, expr1, expr2, msg=None):
798 """Just like self.assertTrue(a is not b), but with a nicer default message."""
799 if expr1 is expr2:
Michael Foord225a0992010-02-18 20:30:09 +0000800 standardMsg = 'unexpectedly identical: %s' % (safe_repr(expr1),)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000801 self.fail(self._formatMessage(msg, standardMsg))
802
803 def assertDictEqual(self, d1, d2, msg=None):
804 self.assert_(isinstance(d1, dict), 'First argument is not a dictionary')
805 self.assert_(isinstance(d2, dict), 'Second argument is not a dictionary')
806
807 if d1 != d2:
Michael Foord674648e2010-06-05 12:58:39 +0000808 standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True))
Michael Foorde37d75f2010-06-05 12:10:52 +0000809 diff = ('\n' + '\n'.join(difflib.ndiff(
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000810 pprint.pformat(d1).splitlines(),
811 pprint.pformat(d2).splitlines())))
Michael Foord674648e2010-06-05 12:58:39 +0000812 standardMsg = self._truncateMessage(standardMsg, diff)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000813 self.fail(self._formatMessage(msg, standardMsg))
814
815 def assertDictContainsSubset(self, expected, actual, msg=None):
816 """Checks whether actual is a superset of expected."""
817 missing = []
818 mismatched = []
819 for key, value in expected.iteritems():
820 if key not in actual:
821 missing.append(key)
822 elif value != actual[key]:
Georg Brandl46cc46a2009-10-01 20:11:14 +0000823 mismatched.append('%s, expected: %s, actual: %s' %
Michael Foordc2294dd2010-02-18 21:37:07 +0000824 (safe_repr(key), safe_repr(value),
825 safe_repr(actual[key])))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000826
827 if not (missing or mismatched):
828 return
829
830 standardMsg = ''
831 if missing:
Michael Foord225a0992010-02-18 20:30:09 +0000832 standardMsg = 'Missing: %s' % ','.join(safe_repr(m) for m in
833 missing)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000834 if mismatched:
835 if standardMsg:
836 standardMsg += '; '
837 standardMsg += 'Mismatched values: %s' % ','.join(mismatched)
838
839 self.fail(self._formatMessage(msg, standardMsg))
840
Michael Foord98e7b762010-03-20 03:00:34 +0000841 def assertItemsEqual(self, expected_seq, actual_seq, msg=None):
842 """An unordered sequence / set specific comparison. It asserts that
843 expected_seq and actual_seq contain the same elements. It is
844 the equivalent of::
845
846 self.assertEqual(sorted(expected_seq), sorted(actual_seq))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000847
848 Raises with an error message listing which elements of expected_seq
849 are missing from actual_seq and vice versa if any.
Michael Foordd0edec32010-02-05 22:55:09 +0000850
Michael Foord98e7b762010-03-20 03:00:34 +0000851 Asserts that each element has the same count in both sequences.
852 Example:
853 - [0, 1, 1] and [1, 0, 1] compare equal.
854 - [0, 0, 1] and [0, 1] compare unequal.
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000855 """
Florent Xicluna1f3b4e12010-03-07 12:14:25 +0000856 with warnings.catch_warnings():
857 if sys.py3kwarning:
858 # Silence Py3k warning raised during the sorting
Florent Xicluna4a0f8b82010-03-21 10:50:44 +0000859 for _msg in ["(code|dict|type) inequality comparisons",
Michael Foord98e7b762010-03-20 03:00:34 +0000860 "builtin_function_or_method order comparisons",
861 "comparing unequal types"]:
Michael Foorda7152552010-03-07 23:10:36 +0000862 warnings.filterwarnings("ignore", _msg, DeprecationWarning)
Florent Xicluna1f3b4e12010-03-07 12:14:25 +0000863 try:
Florent Xicluna1f3b4e12010-03-07 12:14:25 +0000864 expected = sorted(expected_seq)
865 actual = sorted(actual_seq)
Michael Foord98e7b762010-03-20 03:00:34 +0000866 except TypeError:
867 # Unsortable items (example: set(), complex(), ...)
868 expected = list(expected_seq)
869 actual = list(actual_seq)
870 missing, unexpected = unorderable_list_difference(
871 expected, actual, ignore_duplicate=False
872 )
873 else:
874 return self.assertSequenceEqual(expected, actual, msg=msg)
875
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000876 errors = []
877 if missing:
Michael Foord225a0992010-02-18 20:30:09 +0000878 errors.append('Expected, but missing:\n %s' %
Michael Foord98e7b762010-03-20 03:00:34 +0000879 safe_repr(missing))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000880 if unexpected:
Michael Foord225a0992010-02-18 20:30:09 +0000881 errors.append('Unexpected, but present:\n %s' %
Michael Foord98e7b762010-03-20 03:00:34 +0000882 safe_repr(unexpected))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000883 if errors:
884 standardMsg = '\n'.join(errors)
885 self.fail(self._formatMessage(msg, standardMsg))
886
887 def assertMultiLineEqual(self, first, second, msg=None):
888 """Assert that two multi-line strings are equal."""
889 self.assert_(isinstance(first, basestring), (
890 'First argument is not a string'))
891 self.assert_(isinstance(second, basestring), (
892 'Second argument is not a string'))
893
894 if first != second:
Michael Foordf2c25c52010-06-05 13:48:27 +0000895 standardMsg = '%s != %s' % (safe_repr(first, True), safe_repr(second, True))
Michael Foorde37d75f2010-06-05 12:10:52 +0000896 diff = '\n' + ''.join(difflib.ndiff(first.splitlines(True),
Georg Brandl46cc46a2009-10-01 20:11:14 +0000897 second.splitlines(True)))
Michael Foord674648e2010-06-05 12:58:39 +0000898 standardMsg = self._truncateMessage(standardMsg, diff)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000899 self.fail(self._formatMessage(msg, standardMsg))
900
901 def assertLess(self, a, b, msg=None):
902 """Just like self.assertTrue(a < b), but with a nicer default message."""
903 if not a < b:
Michael Foord225a0992010-02-18 20:30:09 +0000904 standardMsg = '%s not less than %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000905 self.fail(self._formatMessage(msg, standardMsg))
906
907 def assertLessEqual(self, a, b, msg=None):
908 """Just like self.assertTrue(a <= b), but with a nicer default message."""
909 if not a <= b:
Michael Foord225a0992010-02-18 20:30:09 +0000910 standardMsg = '%s not less than or equal to %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000911 self.fail(self._formatMessage(msg, standardMsg))
912
913 def assertGreater(self, a, b, msg=None):
914 """Just like self.assertTrue(a > b), but with a nicer default message."""
915 if not a > b:
Michael Foord225a0992010-02-18 20:30:09 +0000916 standardMsg = '%s not greater than %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000917 self.fail(self._formatMessage(msg, standardMsg))
918
919 def assertGreaterEqual(self, a, b, msg=None):
920 """Just like self.assertTrue(a >= b), but with a nicer default message."""
921 if not a >= b:
Michael Foord225a0992010-02-18 20:30:09 +0000922 standardMsg = '%s not greater than or equal to %s' % (safe_repr(a), safe_repr(b))
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000923 self.fail(self._formatMessage(msg, standardMsg))
924
925 def assertIsNone(self, obj, msg=None):
926 """Same as self.assertTrue(obj is None), with a nicer default message."""
927 if obj is not None:
Michael Foord225a0992010-02-18 20:30:09 +0000928 standardMsg = '%s is not None' % (safe_repr(obj),)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000929 self.fail(self._formatMessage(msg, standardMsg))
930
931 def assertIsNotNone(self, obj, msg=None):
932 """Included for symmetry with assertIsNone."""
933 if obj is None:
934 standardMsg = 'unexpectedly None'
935 self.fail(self._formatMessage(msg, standardMsg))
936
Georg Brandlf895cf52009-10-01 20:59:31 +0000937 def assertIsInstance(self, obj, cls, msg=None):
938 """Same as self.assertTrue(isinstance(obj, cls)), with a nicer
939 default message."""
940 if not isinstance(obj, cls):
Michael Foord225a0992010-02-18 20:30:09 +0000941 standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls)
Georg Brandlf895cf52009-10-01 20:59:31 +0000942 self.fail(self._formatMessage(msg, standardMsg))
943
944 def assertNotIsInstance(self, obj, cls, msg=None):
945 """Included for symmetry with assertIsInstance."""
946 if isinstance(obj, cls):
Michael Foord225a0992010-02-18 20:30:09 +0000947 standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls)
Georg Brandlf895cf52009-10-01 20:59:31 +0000948 self.fail(self._formatMessage(msg, standardMsg))
949
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000950 def assertRaisesRegexp(self, expected_exception, expected_regexp,
951 callable_obj=None, *args, **kwargs):
952 """Asserts that the message in a raised exception matches a regexp.
953
954 Args:
955 expected_exception: Exception class expected to be raised.
956 expected_regexp: Regexp (re pattern object or string) expected
957 to be found in error message.
958 callable_obj: Function to be called.
959 args: Extra args.
960 kwargs: Extra kwargs.
961 """
962 context = _AssertRaisesContext(expected_exception, self, expected_regexp)
963 if callable_obj is None:
964 return context
965 with context:
966 callable_obj(*args, **kwargs)
967
Georg Brandlb0eb4d32010-02-07 11:34:15 +0000968 def assertRegexpMatches(self, text, expected_regexp, msg=None):
Michael Foord959c16d2010-05-08 16:40:52 +0000969 """Fail the test unless the text matches the regular expression."""
Georg Brandlb0eb4d32010-02-07 11:34:15 +0000970 if isinstance(expected_regexp, basestring):
971 expected_regexp = re.compile(expected_regexp)
972 if not expected_regexp.search(text):
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000973 msg = msg or "Regexp didn't match"
Georg Brandlb0eb4d32010-02-07 11:34:15 +0000974 msg = '%s: %r not found in %r' % (msg, expected_regexp.pattern, text)
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000975 raise self.failureException(msg)
976
Michael Foorda04c7a02010-04-02 22:55:59 +0000977 def assertNotRegexpMatches(self, text, unexpected_regexp, msg=None):
Michael Foord959c16d2010-05-08 16:40:52 +0000978 """Fail the test if the text matches the regular expression."""
Michael Foorda04c7a02010-04-02 22:55:59 +0000979 if isinstance(unexpected_regexp, basestring):
980 unexpected_regexp = re.compile(unexpected_regexp)
981 match = unexpected_regexp.search(text)
982 if match:
983 msg = msg or "Regexp matched"
984 msg = '%s: %r matches %r in %r' % (msg,
985 text[match.start():match.end()],
986 unexpected_regexp.pattern,
987 text)
988 raise self.failureException(msg)
989
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +0000990
991class FunctionTestCase(TestCase):
992 """A test case that wraps a test function.
993
994 This is useful for slipping pre-existing test functions into the
995 unittest framework. Optionally, set-up and tidy-up functions can be
996 supplied. As with TestCase, the tidy-up ('tearDown') function will
997 always be called if the set-up ('setUp') function ran successfully.
998 """
999
1000 def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
1001 super(FunctionTestCase, self).__init__()
1002 self._setUpFunc = setUp
1003 self._tearDownFunc = tearDown
1004 self._testFunc = testFunc
1005 self._description = description
1006
1007 def setUp(self):
1008 if self._setUpFunc is not None:
1009 self._setUpFunc()
1010
1011 def tearDown(self):
1012 if self._tearDownFunc is not None:
1013 self._tearDownFunc()
1014
1015 def runTest(self):
1016 self._testFunc()
1017
1018 def id(self):
1019 return self._testFunc.__name__
1020
1021 def __eq__(self, other):
1022 if not isinstance(other, self.__class__):
1023 return NotImplemented
1024
1025 return self._setUpFunc == other._setUpFunc and \
1026 self._tearDownFunc == other._tearDownFunc and \
1027 self._testFunc == other._testFunc and \
1028 self._description == other._description
1029
1030 def __ne__(self, other):
1031 return not self == other
1032
1033 def __hash__(self):
1034 return hash((type(self), self._setUpFunc, self._tearDownFunc,
1035 self._testFunc, self._description))
1036
1037 def __str__(self):
Michael Foord225a0992010-02-18 20:30:09 +00001038 return "%s (%s)" % (strclass(self.__class__),
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00001039 self._testFunc.__name__)
1040
1041 def __repr__(self):
Michael Foord225a0992010-02-18 20:30:09 +00001042 return "<%s tec=%s>" % (strclass(self.__class__),
Benjamin Petersond7b0eeb2009-07-19 20:18:21 +00001043 self._testFunc)
1044
1045 def shortDescription(self):
1046 if self._description is not None:
1047 return self._description
1048 doc = self._testFunc.__doc__
1049 return doc and doc.split("\n")[0].strip() or None