1"""Test case implementation""" 2 3import sys 4import functools 5import difflib 6import pprint 7import re 8import warnings 9import collections 10import contextlib 11import traceback 12import types 13 14from . import result 15from .util import (strclass, safe_repr, _count_diff_all_purpose, 16 _count_diff_hashable, _common_shorten_repr) 17 18__unittest = True 19 20_subtest_msg_sentinel = object() 21 22DIFF_OMITTED = ('\nDiff is %s characters long. ' 23 'Set self.maxDiff to None to see it.') 24 25class SkipTest(Exception): 26 """ 27 Raise this exception in a test to skip it. 28 29 Usually you can use TestCase.skipTest() or one of the skipping decorators 30 instead of raising this directly. 31 """ 32 33class _ShouldStop(Exception): 34 """ 35 The test should stop. 36 """ 37 38class _UnexpectedSuccess(Exception): 39 """ 40 The test was supposed to fail, but it didn't! 41 """ 42 43 44class _Outcome(object): 45 def __init__(self, result=None): 46 self.expecting_failure = False 47 self.result = result 48 self.result_supports_subtests = hasattr(result, "addSubTest") 49 self.success = True 50 self.skipped = [] 51 self.expectedFailure = None 52 self.errors = [] 53 54 @contextlib.contextmanager 55 def testPartExecutor(self, test_case, isTest=False): 56 old_success = self.success 57 self.success = True 58 try: 59 yield 60 except KeyboardInterrupt: 61 raise 62 except SkipTest as e: 63 self.success = False 64 self.skipped.append((test_case, str(e))) 65 except _ShouldStop: 66 pass 67 except: 68 exc_info = sys.exc_info() 69 if self.expecting_failure: 70 self.expectedFailure = exc_info 71 else: 72 self.success = False 73 self.errors.append((test_case, exc_info)) 74 # explicitly break a reference cycle: 75 # exc_info -> frame -> exc_info 76 exc_info = None 77 else: 78 if self.result_supports_subtests and self.success: 79 self.errors.append((test_case, None)) 80 finally: 81 self.success = self.success and old_success 82 83 84def _id(obj): 85 return obj 86 87 88_module_cleanups = [] 89def addModuleCleanup(function, /, *args, **kwargs): 90 """Same as addCleanup, except the cleanup items are called even if 91 setUpModule fails (unlike tearDownModule).""" 92 _module_cleanups.append((function, args, kwargs)) 93 94 95def doModuleCleanups(): 96 """Execute all module cleanup functions. Normally called for you after 97 tearDownModule.""" 98 exceptions = [] 99 while _module_cleanups: 100 function, args, kwargs = _module_cleanups.pop() 101 try: 102 function(*args, **kwargs) 103 except Exception as exc: 104 exceptions.append(exc) 105 if exceptions: 106 # Swallows all but first exception. If a multi-exception handler 107 # gets written we should use that here instead. 108 raise exceptions[0] 109 110 111def skip(reason): 112 """ 113 Unconditionally skip a test. 114 """ 115 def decorator(test_item): 116 if not isinstance(test_item, type): 117 @functools.wraps(test_item) 118 def skip_wrapper(*args, **kwargs): 119 raise SkipTest(reason) 120 test_item = skip_wrapper 121 122 test_item.__unittest_skip__ = True 123 test_item.__unittest_skip_why__ = reason 124 return test_item 125 if isinstance(reason, types.FunctionType): 126 test_item = reason 127 reason = '' 128 return decorator(test_item) 129 return decorator 130 131def skipIf(condition, reason): 132 """ 133 Skip a test if the condition is true. 134 """ 135 if condition: 136 return skip(reason) 137 return _id 138 139def skipUnless(condition, reason): 140 """ 141 Skip a test unless the condition is true. 142 """ 143 if not condition: 144 return skip(reason) 145 return _id 146 147def expectedFailure(test_item): 148 test_item.__unittest_expecting_failure__ = True 149 return test_item 150 151def _is_subtype(expected, basetype): 152 if isinstance(expected, tuple): 153 return all(_is_subtype(e, basetype) for e in expected) 154 return isinstance(expected, type) and issubclass(expected, basetype) 155 156class _BaseTestCaseContext: 157 158 def __init__(self, test_case): 159 self.test_case = test_case 160 161 def _raiseFailure(self, standardMsg): 162 msg = self.test_case._formatMessage(self.msg, standardMsg) 163 raise self.test_case.failureException(msg) 164 165class _AssertRaisesBaseContext(_BaseTestCaseContext): 166 167 def __init__(self, expected, test_case, expected_regex=None): 168 _BaseTestCaseContext.__init__(self, test_case) 169 self.expected = expected 170 self.test_case = test_case 171 if expected_regex is not None: 172 expected_regex = re.compile(expected_regex) 173 self.expected_regex = expected_regex 174 self.obj_name = None 175 self.msg = None 176 177 def handle(self, name, args, kwargs): 178 """ 179 If args is empty, assertRaises/Warns is being used as a 180 context manager, so check for a 'msg' kwarg and return self. 181 If args is not empty, call a callable passing positional and keyword 182 arguments. 183 """ 184 try: 185 if not _is_subtype(self.expected, self._base_type): 186 raise TypeError('%s() arg 1 must be %s' % 187 (name, self._base_type_str)) 188 if not args: 189 self.msg = kwargs.pop('msg', None) 190 if kwargs: 191 raise TypeError('%r is an invalid keyword argument for ' 192 'this function' % (next(iter(kwargs)),)) 193 return self 194 195 callable_obj, *args = args 196 try: 197 self.obj_name = callable_obj.__name__ 198 except AttributeError: 199 self.obj_name = str(callable_obj) 200 with self: 201 callable_obj(*args, **kwargs) 202 finally: 203 # bpo-23890: manually break a reference cycle 204 self = None 205 206 207class _AssertRaisesContext(_AssertRaisesBaseContext): 208 """A context manager used to implement TestCase.assertRaises* methods.""" 209 210 _base_type = BaseException 211 _base_type_str = 'an exception type or tuple of exception types' 212 213 def __enter__(self): 214 return self 215 216 def __exit__(self, exc_type, exc_value, tb): 217 if exc_type is None: 218 try: 219 exc_name = self.expected.__name__ 220 except AttributeError: 221 exc_name = str(self.expected) 222 if self.obj_name: 223 self._raiseFailure("{} not raised by {}".format(exc_name, 224 self.obj_name)) 225 else: 226 self._raiseFailure("{} not raised".format(exc_name)) 227 else: 228 traceback.clear_frames(tb) 229 if not issubclass(exc_type, self.expected): 230 # let unexpected exceptions pass through 231 return False 232 # store exception, without traceback, for later retrieval 233 self.exception = exc_value.with_traceback(None) 234 if self.expected_regex is None: 235 return True 236 237 expected_regex = self.expected_regex 238 if not expected_regex.search(str(exc_value)): 239 self._raiseFailure('"{}" does not match "{}"'.format( 240 expected_regex.pattern, str(exc_value))) 241 return True 242 243 __class_getitem__ = classmethod(types.GenericAlias) 244 245 246class _AssertWarnsContext(_AssertRaisesBaseContext): 247 """A context manager used to implement TestCase.assertWarns* methods.""" 248 249 _base_type = Warning 250 _base_type_str = 'a warning type or tuple of warning types' 251 252 def __enter__(self): 253 # The __warningregistry__'s need to be in a pristine state for tests 254 # to work properly. 255 for v in sys.modules.values(): 256 if getattr(v, '__warningregistry__', None): 257 v.__warningregistry__ = {} 258 self.warnings_manager = warnings.catch_warnings(record=True) 259 self.warnings = self.warnings_manager.__enter__() 260 warnings.simplefilter("always", self.expected) 261 return self 262 263 def __exit__(self, exc_type, exc_value, tb): 264 self.warnings_manager.__exit__(exc_type, exc_value, tb) 265 if exc_type is not None: 266 # let unexpected exceptions pass through 267 return 268 try: 269 exc_name = self.expected.__name__ 270 except AttributeError: 271 exc_name = str(self.expected) 272 first_matching = None 273 for m in self.warnings: 274 w = m.message 275 if not isinstance(w, self.expected): 276 continue 277 if first_matching is None: 278 first_matching = w 279 if (self.expected_regex is not None and 280 not self.expected_regex.search(str(w))): 281 continue 282 # store warning for later retrieval 283 self.warning = w 284 self.filename = m.filename 285 self.lineno = m.lineno 286 return 287 # Now we simply try to choose a helpful failure message 288 if first_matching is not None: 289 self._raiseFailure('"{}" does not match "{}"'.format( 290 self.expected_regex.pattern, str(first_matching))) 291 if self.obj_name: 292 self._raiseFailure("{} not triggered by {}".format(exc_name, 293 self.obj_name)) 294 else: 295 self._raiseFailure("{} not triggered".format(exc_name)) 296 297 298 299class _OrderedChainMap(collections.ChainMap): 300 def __iter__(self): 301 seen = set() 302 for mapping in self.maps: 303 for k in mapping: 304 if k not in seen: 305 seen.add(k) 306 yield k 307 308 309class TestCase(object): 310 """A class whose instances are single test cases. 311 312 By default, the test code itself should be placed in a method named 313 'runTest'. 314 315 If the fixture may be used for many test cases, create as 316 many test methods as are needed. When instantiating such a TestCase 317 subclass, specify in the constructor arguments the name of the test method 318 that the instance is to execute. 319 320 Test authors should subclass TestCase for their own tests. Construction 321 and deconstruction of the test's environment ('fixture') can be 322 implemented by overriding the 'setUp' and 'tearDown' methods respectively. 323 324 If it is necessary to override the __init__ method, the base class 325 __init__ method must always be called. It is important that subclasses 326 should not change the signature of their __init__ method, since instances 327 of the classes are instantiated automatically by parts of the framework 328 in order to be run. 329 330 When subclassing TestCase, you can set these attributes: 331 * failureException: determines which exception will be raised when 332 the instance's assertion methods fail; test methods raising this 333 exception will be deemed to have 'failed' rather than 'errored'. 334 * longMessage: determines whether long messages (including repr of 335 objects used in assert methods) will be printed on failure in *addition* 336 to any explicit message passed. 337 * maxDiff: sets the maximum length of a diff in failure messages 338 by assert methods using difflib. It is looked up as an instance 339 attribute so can be configured by individual tests if required. 340 """ 341 342 failureException = AssertionError 343 344 longMessage = True 345 346 maxDiff = 80*8 347 348 # If a string is longer than _diffThreshold, use normal comparison instead 349 # of difflib. See #11763. 350 _diffThreshold = 2**16 351 352 # Attribute used by TestSuite for classSetUp 353 354 _classSetupFailed = False 355 356 _class_cleanups = [] 357 358 def __init__(self, methodName='runTest'): 359 """Create an instance of the class that will use the named test 360 method when executed. Raises a ValueError if the instance does 361 not have a method with the specified name. 362 """ 363 self._testMethodName = methodName 364 self._outcome = None 365 self._testMethodDoc = 'No test' 366 try: 367 testMethod = getattr(self, methodName) 368 except AttributeError: 369 if methodName != 'runTest': 370 # we allow instantiation with no explicit method name 371 # but not an *incorrect* or missing method name 372 raise ValueError("no such test method in %s: %s" % 373 (self.__class__, methodName)) 374 else: 375 self._testMethodDoc = testMethod.__doc__ 376 self._cleanups = [] 377 self._subtest = None 378 379 # Map types to custom assertEqual functions that will compare 380 # instances of said type in more detail to generate a more useful 381 # error message. 382 self._type_equality_funcs = {} 383 self.addTypeEqualityFunc(dict, 'assertDictEqual') 384 self.addTypeEqualityFunc(list, 'assertListEqual') 385 self.addTypeEqualityFunc(tuple, 'assertTupleEqual') 386 self.addTypeEqualityFunc(set, 'assertSetEqual') 387 self.addTypeEqualityFunc(frozenset, 'assertSetEqual') 388 self.addTypeEqualityFunc(str, 'assertMultiLineEqual') 389 390 def addTypeEqualityFunc(self, typeobj, function): 391 """Add a type specific assertEqual style function to compare a type. 392 393 This method is for use by TestCase subclasses that need to register 394 their own type equality functions to provide nicer error messages. 395 396 Args: 397 typeobj: The data type to call this function on when both values 398 are of the same type in assertEqual(). 399 function: The callable taking two arguments and an optional 400 msg= argument that raises self.failureException with a 401 useful error message when the two arguments are not equal. 402 """ 403 self._type_equality_funcs[typeobj] = function 404 405 def addCleanup(self, function, /, *args, **kwargs): 406 """Add a function, with arguments, to be called when the test is 407 completed. Functions added are called on a LIFO basis and are 408 called after tearDown on test failure or success. 409 410 Cleanup items are called even if setUp fails (unlike tearDown).""" 411 self._cleanups.append((function, args, kwargs)) 412 413 @classmethod 414 def addClassCleanup(cls, function, /, *args, **kwargs): 415 """Same as addCleanup, except the cleanup items are called even if 416 setUpClass fails (unlike tearDownClass).""" 417 cls._class_cleanups.append((function, args, kwargs)) 418 419 def setUp(self): 420 "Hook method for setting up the test fixture before exercising it." 421 pass 422 423 def tearDown(self): 424 "Hook method for deconstructing the test fixture after testing it." 425 pass 426 427 @classmethod 428 def setUpClass(cls): 429 "Hook method for setting up class fixture before running tests in the class." 430 431 @classmethod 432 def tearDownClass(cls): 433 "Hook method for deconstructing the class fixture after running all tests in the class." 434 435 def countTestCases(self): 436 return 1 437 438 def defaultTestResult(self): 439 return result.TestResult() 440 441 def shortDescription(self): 442 """Returns a one-line description of the test, or None if no 443 description has been provided. 444 445 The default implementation of this method returns the first line of 446 the specified test method's docstring. 447 """ 448 doc = self._testMethodDoc 449 return doc.strip().split("\n")[0].strip() if doc else None 450 451 452 def id(self): 453 return "%s.%s" % (strclass(self.__class__), self._testMethodName) 454 455 def __eq__(self, other): 456 if type(self) is not type(other): 457 return NotImplemented 458 459 return self._testMethodName == other._testMethodName 460 461 def __hash__(self): 462 return hash((type(self), self._testMethodName)) 463 464 def __str__(self): 465 return "%s (%s)" % (self._testMethodName, strclass(self.__class__)) 466 467 def __repr__(self): 468 return "<%s testMethod=%s>" % \ 469 (strclass(self.__class__), self._testMethodName) 470 471 def _addSkip(self, result, test_case, reason): 472 addSkip = getattr(result, 'addSkip', None) 473 if addSkip is not None: 474 addSkip(test_case, reason) 475 else: 476 warnings.warn("TestResult has no addSkip method, skips not reported", 477 RuntimeWarning, 2) 478 result.addSuccess(test_case) 479 480 @contextlib.contextmanager 481 def subTest(self, msg=_subtest_msg_sentinel, **params): 482 """Return a context manager that will return the enclosed block 483 of code in a subtest identified by the optional message and 484 keyword parameters. A failure in the subtest marks the test 485 case as failed but resumes execution at the end of the enclosed 486 block, allowing further test code to be executed. 487 """ 488 if self._outcome is None or not self._outcome.result_supports_subtests: 489 yield 490 return 491 parent = self._subtest 492 if parent is None: 493 params_map = _OrderedChainMap(params) 494 else: 495 params_map = parent.params.new_child(params) 496 self._subtest = _SubTest(self, msg, params_map) 497 try: 498 with self._outcome.testPartExecutor(self._subtest, isTest=True): 499 yield 500 if not self._outcome.success: 501 result = self._outcome.result 502 if result is not None and result.failfast: 503 raise _ShouldStop 504 elif self._outcome.expectedFailure: 505 # If the test is expecting a failure, we really want to 506 # stop now and register the expected failure. 507 raise _ShouldStop 508 finally: 509 self._subtest = parent 510 511 def _feedErrorsToResult(self, result, errors): 512 for test, exc_info in errors: 513 if isinstance(test, _SubTest): 514 result.addSubTest(test.test_case, test, exc_info) 515 elif exc_info is not None: 516 if issubclass(exc_info[0], self.failureException): 517 result.addFailure(test, exc_info) 518 else: 519 result.addError(test, exc_info) 520 521 def _addExpectedFailure(self, result, exc_info): 522 try: 523 addExpectedFailure = result.addExpectedFailure 524 except AttributeError: 525 warnings.warn("TestResult has no addExpectedFailure method, reporting as passes", 526 RuntimeWarning) 527 result.addSuccess(self) 528 else: 529 addExpectedFailure(self, exc_info) 530 531 def _addUnexpectedSuccess(self, result): 532 try: 533 addUnexpectedSuccess = result.addUnexpectedSuccess 534 except AttributeError: 535 warnings.warn("TestResult has no addUnexpectedSuccess method, reporting as failure", 536 RuntimeWarning) 537 # We need to pass an actual exception and traceback to addFailure, 538 # otherwise the legacy result can choke. 539 try: 540 raise _UnexpectedSuccess from None 541 except _UnexpectedSuccess: 542 result.addFailure(self, sys.exc_info()) 543 else: 544 addUnexpectedSuccess(self) 545 546 def _callSetUp(self): 547 self.setUp() 548 549 def _callTestMethod(self, method): 550 method() 551 552 def _callTearDown(self): 553 self.tearDown() 554 555 def _callCleanup(self, function, /, *args, **kwargs): 556 function(*args, **kwargs) 557 558 def run(self, result=None): 559 if result is None: 560 result = self.defaultTestResult() 561 startTestRun = getattr(result, 'startTestRun', None) 562 stopTestRun = getattr(result, 'stopTestRun', None) 563 if startTestRun is not None: 564 startTestRun() 565 else: 566 stopTestRun = None 567 568 result.startTest(self) 569 try: 570 testMethod = getattr(self, self._testMethodName) 571 if (getattr(self.__class__, "__unittest_skip__", False) or 572 getattr(testMethod, "__unittest_skip__", False)): 573 # If the class or method was skipped. 574 skip_why = (getattr(self.__class__, '__unittest_skip_why__', '') 575 or getattr(testMethod, '__unittest_skip_why__', '')) 576 self._addSkip(result, self, skip_why) 577 return result 578 579 expecting_failure = ( 580 getattr(self, "__unittest_expecting_failure__", False) or 581 getattr(testMethod, "__unittest_expecting_failure__", False) 582 ) 583 outcome = _Outcome(result) 584 try: 585 self._outcome = outcome 586 587 with outcome.testPartExecutor(self): 588 self._callSetUp() 589 if outcome.success: 590 outcome.expecting_failure = expecting_failure 591 with outcome.testPartExecutor(self, isTest=True): 592 self._callTestMethod(testMethod) 593 outcome.expecting_failure = False 594 with outcome.testPartExecutor(self): 595 self._callTearDown() 596 597 self.doCleanups() 598 for test, reason in outcome.skipped: 599 self._addSkip(result, test, reason) 600 self._feedErrorsToResult(result, outcome.errors) 601 if outcome.success: 602 if expecting_failure: 603 if outcome.expectedFailure: 604 self._addExpectedFailure(result, outcome.expectedFailure) 605 else: 606 self._addUnexpectedSuccess(result) 607 else: 608 result.addSuccess(self) 609 return result 610 finally: 611 # explicitly break reference cycles: 612 # outcome.errors -> frame -> outcome -> outcome.errors 613 # outcome.expectedFailure -> frame -> outcome -> outcome.expectedFailure 614 outcome.errors.clear() 615 outcome.expectedFailure = None 616 617 # clear the outcome, no more needed 618 self._outcome = None 619 620 finally: 621 result.stopTest(self) 622 if stopTestRun is not None: 623 stopTestRun() 624 625 def doCleanups(self): 626 """Execute all cleanup functions. Normally called for you after 627 tearDown.""" 628 outcome = self._outcome or _Outcome() 629 while self._cleanups: 630 function, args, kwargs = self._cleanups.pop() 631 with outcome.testPartExecutor(self): 632 self._callCleanup(function, *args, **kwargs) 633 634 # return this for backwards compatibility 635 # even though we no longer use it internally 636 return outcome.success 637 638 @classmethod 639 def doClassCleanups(cls): 640 """Execute all class cleanup functions. Normally called for you after 641 tearDownClass.""" 642 cls.tearDown_exceptions = [] 643 while cls._class_cleanups: 644 function, args, kwargs = cls._class_cleanups.pop() 645 try: 646 function(*args, **kwargs) 647 except Exception: 648 cls.tearDown_exceptions.append(sys.exc_info()) 649 650 def __call__(self, *args, **kwds): 651 return self.run(*args, **kwds) 652 653 def debug(self): 654 """Run the test without collecting errors in a TestResult""" 655 testMethod = getattr(self, self._testMethodName) 656 if (getattr(self.__class__, "__unittest_skip__", False) or 657 getattr(testMethod, "__unittest_skip__", False)): 658 # If the class or method was skipped. 659 skip_why = (getattr(self.__class__, '__unittest_skip_why__', '') 660 or getattr(testMethod, '__unittest_skip_why__', '')) 661 raise SkipTest(skip_why) 662 663 self._callSetUp() 664 self._callTestMethod(testMethod) 665 self._callTearDown() 666 while self._cleanups: 667 function, args, kwargs = self._cleanups.pop() 668 self._callCleanup(function, *args, **kwargs) 669 670 def skipTest(self, reason): 671 """Skip this test.""" 672 raise SkipTest(reason) 673 674 def fail(self, msg=None): 675 """Fail immediately, with the given message.""" 676 raise self.failureException(msg) 677 678 def assertFalse(self, expr, msg=None): 679 """Check that the expression is false.""" 680 if expr: 681 msg = self._formatMessage(msg, "%s is not false" % safe_repr(expr)) 682 raise self.failureException(msg) 683 684 def assertTrue(self, expr, msg=None): 685 """Check that the expression is true.""" 686 if not expr: 687 msg = self._formatMessage(msg, "%s is not true" % safe_repr(expr)) 688 raise self.failureException(msg) 689 690 def _formatMessage(self, msg, standardMsg): 691 """Honour the longMessage attribute when generating failure messages. 692 If longMessage is False this means: 693 * Use only an explicit message if it is provided 694 * Otherwise use the standard message for the assert 695 696 If longMessage is True: 697 * Use the standard message 698 * If an explicit message is provided, plus ' : ' and the explicit message 699 """ 700 if not self.longMessage: 701 return msg or standardMsg 702 if msg is None: 703 return standardMsg 704 try: 705 # don't switch to '{}' formatting in Python 2.X 706 # it changes the way unicode input is handled 707 return '%s : %s' % (standardMsg, msg) 708 except UnicodeDecodeError: 709 return '%s : %s' % (safe_repr(standardMsg), safe_repr(msg)) 710 711 def assertRaises(self, expected_exception, *args, **kwargs): 712 """Fail unless an exception of class expected_exception is raised 713 by the callable when invoked with specified positional and 714 keyword arguments. If a different type of exception is 715 raised, it will not be caught, and the test case will be 716 deemed to have suffered an error, exactly as for an 717 unexpected exception. 718 719 If called with the callable and arguments omitted, will return a 720 context object used like this:: 721 722 with self.assertRaises(SomeException): 723 do_something() 724 725 An optional keyword argument 'msg' can be provided when assertRaises 726 is used as a context object. 727 728 The context manager keeps a reference to the exception as 729 the 'exception' attribute. This allows you to inspect the 730 exception after the assertion:: 731 732 with self.assertRaises(SomeException) as cm: 733 do_something() 734 the_exception = cm.exception 735 self.assertEqual(the_exception.error_code, 3) 736 """ 737 context = _AssertRaisesContext(expected_exception, self) 738 try: 739 return context.handle('assertRaises', args, kwargs) 740 finally: 741 # bpo-23890: manually break a reference cycle 742 context = None 743 744 def assertWarns(self, expected_warning, *args, **kwargs): 745 """Fail unless a warning of class warnClass is triggered 746 by the callable when invoked with specified positional and 747 keyword arguments. If a different type of warning is 748 triggered, it will not be handled: depending on the other 749 warning filtering rules in effect, it might be silenced, printed 750 out, or raised as an exception. 751 752 If called with the callable and arguments omitted, will return a 753 context object used like this:: 754 755 with self.assertWarns(SomeWarning): 756 do_something() 757 758 An optional keyword argument 'msg' can be provided when assertWarns 759 is used as a context object. 760 761 The context manager keeps a reference to the first matching 762 warning as the 'warning' attribute; similarly, the 'filename' 763 and 'lineno' attributes give you information about the line 764 of Python code from which the warning was triggered. 765 This allows you to inspect the warning after the assertion:: 766 767 with self.assertWarns(SomeWarning) as cm: 768 do_something() 769 the_warning = cm.warning 770 self.assertEqual(the_warning.some_attribute, 147) 771 """ 772 context = _AssertWarnsContext(expected_warning, self) 773 return context.handle('assertWarns', args, kwargs) 774 775 def assertLogs(self, logger=None, level=None): 776 """Fail unless a log message of level *level* or higher is emitted 777 on *logger_name* or its children. If omitted, *level* defaults to 778 INFO and *logger* defaults to the root logger. 779 780 This method must be used as a context manager, and will yield 781 a recording object with two attributes: `output` and `records`. 782 At the end of the context manager, the `output` attribute will 783 be a list of the matching formatted log messages and the 784 `records` attribute will be a list of the corresponding LogRecord 785 objects. 786 787 Example:: 788 789 with self.assertLogs('foo', level='INFO') as cm: 790 logging.getLogger('foo').info('first message') 791 logging.getLogger('foo.bar').error('second message') 792 self.assertEqual(cm.output, ['INFO:foo:first message', 793 'ERROR:foo.bar:second message']) 794 """ 795 # Lazy import to avoid importing logging if it is not needed. 796 from ._log import _AssertLogsContext 797 return _AssertLogsContext(self, logger, level) 798 799 def _getAssertEqualityFunc(self, first, second): 800 """Get a detailed comparison function for the types of the two args. 801 802 Returns: A callable accepting (first, second, msg=None) that will 803 raise a failure exception if first != second with a useful human 804 readable error message for those types. 805 """ 806 # 807 # NOTE(gregory.p.smith): I considered isinstance(first, type(second)) 808 # and vice versa. I opted for the conservative approach in case 809 # subclasses are not intended to be compared in detail to their super 810 # class instances using a type equality func. This means testing 811 # subtypes won't automagically use the detailed comparison. Callers 812 # should use their type specific assertSpamEqual method to compare 813 # subclasses if the detailed comparison is desired and appropriate. 814 # See the discussion in http://bugs.python.org/issue2578. 815 # 816 if type(first) is type(second): 817 asserter = self._type_equality_funcs.get(type(first)) 818 if asserter is not None: 819 if isinstance(asserter, str): 820 asserter = getattr(self, asserter) 821 return asserter 822 823 return self._baseAssertEqual 824 825 def _baseAssertEqual(self, first, second, msg=None): 826 """The default assertEqual implementation, not type specific.""" 827 if not first == second: 828 standardMsg = '%s != %s' % _common_shorten_repr(first, second) 829 msg = self._formatMessage(msg, standardMsg) 830 raise self.failureException(msg) 831 832 def assertEqual(self, first, second, msg=None): 833 """Fail if the two objects are unequal as determined by the '==' 834 operator. 835 """ 836 assertion_func = self._getAssertEqualityFunc(first, second) 837 assertion_func(first, second, msg=msg) 838 839 def assertNotEqual(self, first, second, msg=None): 840 """Fail if the two objects are equal as determined by the '!=' 841 operator. 842 """ 843 if not first != second: 844 msg = self._formatMessage(msg, '%s == %s' % (safe_repr(first), 845 safe_repr(second))) 846 raise self.failureException(msg) 847 848 def assertAlmostEqual(self, first, second, places=None, msg=None, 849 delta=None): 850 """Fail if the two objects are unequal as determined by their 851 difference rounded to the given number of decimal places 852 (default 7) and comparing to zero, or by comparing that the 853 difference between the two objects is more than the given 854 delta. 855 856 Note that decimal places (from zero) are usually not the same 857 as significant digits (measured from the most significant digit). 858 859 If the two objects compare equal then they will automatically 860 compare almost equal. 861 """ 862 if first == second: 863 # shortcut 864 return 865 if delta is not None and places is not None: 866 raise TypeError("specify delta or places not both") 867 868 diff = abs(first - second) 869 if delta is not None: 870 if diff <= delta: 871 return 872 873 standardMsg = '%s != %s within %s delta (%s difference)' % ( 874 safe_repr(first), 875 safe_repr(second), 876 safe_repr(delta), 877 safe_repr(diff)) 878 else: 879 if places is None: 880 places = 7 881 882 if round(diff, places) == 0: 883 return 884 885 standardMsg = '%s != %s within %r places (%s difference)' % ( 886 safe_repr(first), 887 safe_repr(second), 888 places, 889 safe_repr(diff)) 890 msg = self._formatMessage(msg, standardMsg) 891 raise self.failureException(msg) 892 893 def assertNotAlmostEqual(self, first, second, places=None, msg=None, 894 delta=None): 895 """Fail if the two objects are equal as determined by their 896 difference rounded to the given number of decimal places 897 (default 7) and comparing to zero, or by comparing that the 898 difference between the two objects is less than the given delta. 899 900 Note that decimal places (from zero) are usually not the same 901 as significant digits (measured from the most significant digit). 902 903 Objects that are equal automatically fail. 904 """ 905 if delta is not None and places is not None: 906 raise TypeError("specify delta or places not both") 907 diff = abs(first - second) 908 if delta is not None: 909 if not (first == second) and diff > delta: 910 return 911 standardMsg = '%s == %s within %s delta (%s difference)' % ( 912 safe_repr(first), 913 safe_repr(second), 914 safe_repr(delta), 915 safe_repr(diff)) 916 else: 917 if places is None: 918 places = 7 919 if not (first == second) and round(diff, places) != 0: 920 return 921 standardMsg = '%s == %s within %r places' % (safe_repr(first), 922 safe_repr(second), 923 places) 924 925 msg = self._formatMessage(msg, standardMsg) 926 raise self.failureException(msg) 927 928 def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None): 929 """An equality assertion for ordered sequences (like lists and tuples). 930 931 For the purposes of this function, a valid ordered sequence type is one 932 which can be indexed, has a length, and has an equality operator. 933 934 Args: 935 seq1: The first sequence to compare. 936 seq2: The second sequence to compare. 937 seq_type: The expected datatype of the sequences, or None if no 938 datatype should be enforced. 939 msg: Optional message to use on failure instead of a list of 940 differences. 941 """ 942 if seq_type is not None: 943 seq_type_name = seq_type.__name__ 944 if not isinstance(seq1, seq_type): 945 raise self.failureException('First sequence is not a %s: %s' 946 % (seq_type_name, safe_repr(seq1))) 947 if not isinstance(seq2, seq_type): 948 raise self.failureException('Second sequence is not a %s: %s' 949 % (seq_type_name, safe_repr(seq2))) 950 else: 951 seq_type_name = "sequence" 952 953 differing = None 954 try: 955 len1 = len(seq1) 956 except (TypeError, NotImplementedError): 957 differing = 'First %s has no length. Non-sequence?' % ( 958 seq_type_name) 959 960 if differing is None: 961 try: 962 len2 = len(seq2) 963 except (TypeError, NotImplementedError): 964 differing = 'Second %s has no length. Non-sequence?' % ( 965 seq_type_name) 966 967 if differing is None: 968 if seq1 == seq2: 969 return 970 971 differing = '%ss differ: %s != %s\n' % ( 972 (seq_type_name.capitalize(),) + 973 _common_shorten_repr(seq1, seq2)) 974 975 for i in range(min(len1, len2)): 976 try: 977 item1 = seq1[i] 978 except (TypeError, IndexError, NotImplementedError): 979 differing += ('\nUnable to index element %d of first %s\n' % 980 (i, seq_type_name)) 981 break 982 983 try: 984 item2 = seq2[i] 985 except (TypeError, IndexError, NotImplementedError): 986 differing += ('\nUnable to index element %d of second %s\n' % 987 (i, seq_type_name)) 988 break 989 990 if item1 != item2: 991 differing += ('\nFirst differing element %d:\n%s\n%s\n' % 992 ((i,) + _common_shorten_repr(item1, item2))) 993 break 994 else: 995 if (len1 == len2 and seq_type is None and 996 type(seq1) != type(seq2)): 997 # The sequences are the same, but have differing types. 998 return 999 1000 if len1 > len2: 1001 differing += ('\nFirst %s contains %d additional ' 1002 'elements.\n' % (seq_type_name, len1 - len2)) 1003 try: 1004 differing += ('First extra element %d:\n%s\n' % 1005 (len2, safe_repr(seq1[len2]))) 1006 except (TypeError, IndexError, NotImplementedError): 1007 differing += ('Unable to index element %d ' 1008 'of first %s\n' % (len2, seq_type_name)) 1009 elif len1 < len2: 1010 differing += ('\nSecond %s contains %d additional ' 1011 'elements.\n' % (seq_type_name, len2 - len1)) 1012 try: 1013 differing += ('First extra element %d:\n%s\n' % 1014 (len1, safe_repr(seq2[len1]))) 1015 except (TypeError, IndexError, NotImplementedError): 1016 differing += ('Unable to index element %d ' 1017 'of second %s\n' % (len1, seq_type_name)) 1018 standardMsg = differing 1019 diffMsg = '\n' + '\n'.join( 1020 difflib.ndiff(pprint.pformat(seq1).splitlines(), 1021 pprint.pformat(seq2).splitlines())) 1022 1023 standardMsg = self._truncateMessage(standardMsg, diffMsg) 1024 msg = self._formatMessage(msg, standardMsg) 1025 self.fail(msg) 1026 1027 def _truncateMessage(self, message, diff): 1028 max_diff = self.maxDiff 1029 if max_diff is None or len(diff) <= max_diff: 1030 return message + diff 1031 return message + (DIFF_OMITTED % len(diff)) 1032 1033 def assertListEqual(self, list1, list2, msg=None): 1034 """A list-specific equality assertion. 1035 1036 Args: 1037 list1: The first list to compare. 1038 list2: The second list to compare. 1039 msg: Optional message to use on failure instead of a list of 1040 differences. 1041 1042 """ 1043 self.assertSequenceEqual(list1, list2, msg, seq_type=list) 1044 1045 def assertTupleEqual(self, tuple1, tuple2, msg=None): 1046 """A tuple-specific equality assertion. 1047 1048 Args: 1049 tuple1: The first tuple to compare. 1050 tuple2: The second tuple to compare. 1051 msg: Optional message to use on failure instead of a list of 1052 differences. 1053 """ 1054 self.assertSequenceEqual(tuple1, tuple2, msg, seq_type=tuple) 1055 1056 def assertSetEqual(self, set1, set2, msg=None): 1057 """A set-specific equality assertion. 1058 1059 Args: 1060 set1: The first set to compare. 1061 set2: The second set to compare. 1062 msg: Optional message to use on failure instead of a list of 1063 differences. 1064 1065 assertSetEqual uses ducktyping to support different types of sets, and 1066 is optimized for sets specifically (parameters must support a 1067 difference method). 1068 """ 1069 try: 1070 difference1 = set1.difference(set2) 1071 except TypeError as e: 1072 self.fail('invalid type when attempting set difference: %s' % e) 1073 except AttributeError as e: 1074 self.fail('first argument does not support set difference: %s' % e) 1075 1076 try: 1077 difference2 = set2.difference(set1) 1078 except TypeError as e: 1079 self.fail('invalid type when attempting set difference: %s' % e) 1080 except AttributeError as e: 1081 self.fail('second argument does not support set difference: %s' % e) 1082 1083 if not (difference1 or difference2): 1084 return 1085 1086 lines = [] 1087 if difference1: 1088 lines.append('Items in the first set but not the second:') 1089 for item in difference1: 1090 lines.append(repr(item)) 1091 if difference2: 1092 lines.append('Items in the second set but not the first:') 1093 for item in difference2: 1094 lines.append(repr(item)) 1095 1096 standardMsg = '\n'.join(lines) 1097 self.fail(self._formatMessage(msg, standardMsg)) 1098 1099 def assertIn(self, member, container, msg=None): 1100 """Just like self.assertTrue(a in b), but with a nicer default message.""" 1101 if member not in container: 1102 standardMsg = '%s not found in %s' % (safe_repr(member), 1103 safe_repr(container)) 1104 self.fail(self._formatMessage(msg, standardMsg)) 1105 1106 def assertNotIn(self, member, container, msg=None): 1107 """Just like self.assertTrue(a not in b), but with a nicer default message.""" 1108 if member in container: 1109 standardMsg = '%s unexpectedly found in %s' % (safe_repr(member), 1110 safe_repr(container)) 1111 self.fail(self._formatMessage(msg, standardMsg)) 1112 1113 def assertIs(self, expr1, expr2, msg=None): 1114 """Just like self.assertTrue(a is b), but with a nicer default message.""" 1115 if expr1 is not expr2: 1116 standardMsg = '%s is not %s' % (safe_repr(expr1), 1117 safe_repr(expr2)) 1118 self.fail(self._formatMessage(msg, standardMsg)) 1119 1120 def assertIsNot(self, expr1, expr2, msg=None): 1121 """Just like self.assertTrue(a is not b), but with a nicer default message.""" 1122 if expr1 is expr2: 1123 standardMsg = 'unexpectedly identical: %s' % (safe_repr(expr1),) 1124 self.fail(self._formatMessage(msg, standardMsg)) 1125 1126 def assertDictEqual(self, d1, d2, msg=None): 1127 self.assertIsInstance(d1, dict, 'First argument is not a dictionary') 1128 self.assertIsInstance(d2, dict, 'Second argument is not a dictionary') 1129 1130 if d1 != d2: 1131 standardMsg = '%s != %s' % _common_shorten_repr(d1, d2) 1132 diff = ('\n' + '\n'.join(difflib.ndiff( 1133 pprint.pformat(d1).splitlines(), 1134 pprint.pformat(d2).splitlines()))) 1135 standardMsg = self._truncateMessage(standardMsg, diff) 1136 self.fail(self._formatMessage(msg, standardMsg)) 1137 1138 def assertDictContainsSubset(self, subset, dictionary, msg=None): 1139 """Checks whether dictionary is a superset of subset.""" 1140 warnings.warn('assertDictContainsSubset is deprecated', 1141 DeprecationWarning) 1142 missing = [] 1143 mismatched = [] 1144 for key, value in subset.items(): 1145 if key not in dictionary: 1146 missing.append(key) 1147 elif value != dictionary[key]: 1148 mismatched.append('%s, expected: %s, actual: %s' % 1149 (safe_repr(key), safe_repr(value), 1150 safe_repr(dictionary[key]))) 1151 1152 if not (missing or mismatched): 1153 return 1154 1155 standardMsg = '' 1156 if missing: 1157 standardMsg = 'Missing: %s' % ','.join(safe_repr(m) for m in 1158 missing) 1159 if mismatched: 1160 if standardMsg: 1161 standardMsg += '; ' 1162 standardMsg += 'Mismatched values: %s' % ','.join(mismatched) 1163 1164 self.fail(self._formatMessage(msg, standardMsg)) 1165 1166 1167 def assertCountEqual(self, first, second, msg=None): 1168 """Asserts that two iterables have the same elements, the same number of 1169 times, without regard to order. 1170 1171 self.assertEqual(Counter(list(first)), 1172 Counter(list(second))) 1173 1174 Example: 1175 - [0, 1, 1] and [1, 0, 1] compare equal. 1176 - [0, 0, 1] and [0, 1] compare unequal. 1177 1178 """ 1179 first_seq, second_seq = list(first), list(second) 1180 try: 1181 first = collections.Counter(first_seq) 1182 second = collections.Counter(second_seq) 1183 except TypeError: 1184 # Handle case with unhashable elements 1185 differences = _count_diff_all_purpose(first_seq, second_seq) 1186 else: 1187 if first == second: 1188 return 1189 differences = _count_diff_hashable(first_seq, second_seq) 1190 1191 if differences: 1192 standardMsg = 'Element counts were not equal:\n' 1193 lines = ['First has %d, Second has %d: %r' % diff for diff in differences] 1194 diffMsg = '\n'.join(lines) 1195 standardMsg = self._truncateMessage(standardMsg, diffMsg) 1196 msg = self._formatMessage(msg, standardMsg) 1197 self.fail(msg) 1198 1199 def assertMultiLineEqual(self, first, second, msg=None): 1200 """Assert that two multi-line strings are equal.""" 1201 self.assertIsInstance(first, str, 'First argument is not a string') 1202 self.assertIsInstance(second, str, 'Second argument is not a string') 1203 1204 if first != second: 1205 # don't use difflib if the strings are too long 1206 if (len(first) > self._diffThreshold or 1207 len(second) > self._diffThreshold): 1208 self._baseAssertEqual(first, second, msg) 1209 firstlines = first.splitlines(keepends=True) 1210 secondlines = second.splitlines(keepends=True) 1211 if len(firstlines) == 1 and first.strip('\r\n') == first: 1212 firstlines = [first + '\n'] 1213 secondlines = [second + '\n'] 1214 standardMsg = '%s != %s' % _common_shorten_repr(first, second) 1215 diff = '\n' + ''.join(difflib.ndiff(firstlines, secondlines)) 1216 standardMsg = self._truncateMessage(standardMsg, diff) 1217 self.fail(self._formatMessage(msg, standardMsg)) 1218 1219 def assertLess(self, a, b, msg=None): 1220 """Just like self.assertTrue(a < b), but with a nicer default message.""" 1221 if not a < b: 1222 standardMsg = '%s not less than %s' % (safe_repr(a), safe_repr(b)) 1223 self.fail(self._formatMessage(msg, standardMsg)) 1224 1225 def assertLessEqual(self, a, b, msg=None): 1226 """Just like self.assertTrue(a <= b), but with a nicer default message.""" 1227 if not a <= b: 1228 standardMsg = '%s not less than or equal to %s' % (safe_repr(a), safe_repr(b)) 1229 self.fail(self._formatMessage(msg, standardMsg)) 1230 1231 def assertGreater(self, a, b, msg=None): 1232 """Just like self.assertTrue(a > b), but with a nicer default message.""" 1233 if not a > b: 1234 standardMsg = '%s not greater than %s' % (safe_repr(a), safe_repr(b)) 1235 self.fail(self._formatMessage(msg, standardMsg)) 1236 1237 def assertGreaterEqual(self, a, b, msg=None): 1238 """Just like self.assertTrue(a >= b), but with a nicer default message.""" 1239 if not a >= b: 1240 standardMsg = '%s not greater than or equal to %s' % (safe_repr(a), safe_repr(b)) 1241 self.fail(self._formatMessage(msg, standardMsg)) 1242 1243 def assertIsNone(self, obj, msg=None): 1244 """Same as self.assertTrue(obj is None), with a nicer default message.""" 1245 if obj is not None: 1246 standardMsg = '%s is not None' % (safe_repr(obj),) 1247 self.fail(self._formatMessage(msg, standardMsg)) 1248 1249 def assertIsNotNone(self, obj, msg=None): 1250 """Included for symmetry with assertIsNone.""" 1251 if obj is None: 1252 standardMsg = 'unexpectedly None' 1253 self.fail(self._formatMessage(msg, standardMsg)) 1254 1255 def assertIsInstance(self, obj, cls, msg=None): 1256 """Same as self.assertTrue(isinstance(obj, cls)), with a nicer 1257 default message.""" 1258 if not isinstance(obj, cls): 1259 standardMsg = '%s is not an instance of %r' % (safe_repr(obj), cls) 1260 self.fail(self._formatMessage(msg, standardMsg)) 1261 1262 def assertNotIsInstance(self, obj, cls, msg=None): 1263 """Included for symmetry with assertIsInstance.""" 1264 if isinstance(obj, cls): 1265 standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls) 1266 self.fail(self._formatMessage(msg, standardMsg)) 1267 1268 def assertRaisesRegex(self, expected_exception, expected_regex, 1269 *args, **kwargs): 1270 """Asserts that the message in a raised exception matches a regex. 1271 1272 Args: 1273 expected_exception: Exception class expected to be raised. 1274 expected_regex: Regex (re.Pattern object or string) expected 1275 to be found in error message. 1276 args: Function to be called and extra positional args. 1277 kwargs: Extra kwargs. 1278 msg: Optional message used in case of failure. Can only be used 1279 when assertRaisesRegex is used as a context manager. 1280 """ 1281 context = _AssertRaisesContext(expected_exception, self, expected_regex) 1282 return context.handle('assertRaisesRegex', args, kwargs) 1283 1284 def assertWarnsRegex(self, expected_warning, expected_regex, 1285 *args, **kwargs): 1286 """Asserts that the message in a triggered warning matches a regexp. 1287 Basic functioning is similar to assertWarns() with the addition 1288 that only warnings whose messages also match the regular expression 1289 are considered successful matches. 1290 1291 Args: 1292 expected_warning: Warning class expected to be triggered. 1293 expected_regex: Regex (re.Pattern object or string) expected 1294 to be found in error message. 1295 args: Function to be called and extra positional args. 1296 kwargs: Extra kwargs. 1297 msg: Optional message used in case of failure. Can only be used 1298 when assertWarnsRegex is used as a context manager. 1299 """ 1300 context = _AssertWarnsContext(expected_warning, self, expected_regex) 1301 return context.handle('assertWarnsRegex', args, kwargs) 1302 1303 def assertRegex(self, text, expected_regex, msg=None): 1304 """Fail the test unless the text matches the regular expression.""" 1305 if isinstance(expected_regex, (str, bytes)): 1306 assert expected_regex, "expected_regex must not be empty." 1307 expected_regex = re.compile(expected_regex) 1308 if not expected_regex.search(text): 1309 standardMsg = "Regex didn't match: %r not found in %r" % ( 1310 expected_regex.pattern, text) 1311 # _formatMessage ensures the longMessage option is respected 1312 msg = self._formatMessage(msg, standardMsg) 1313 raise self.failureException(msg) 1314 1315 def assertNotRegex(self, text, unexpected_regex, msg=None): 1316 """Fail the test if the text matches the regular expression.""" 1317 if isinstance(unexpected_regex, (str, bytes)): 1318 unexpected_regex = re.compile(unexpected_regex) 1319 match = unexpected_regex.search(text) 1320 if match: 1321 standardMsg = 'Regex matched: %r matches %r in %r' % ( 1322 text[match.start() : match.end()], 1323 unexpected_regex.pattern, 1324 text) 1325 # _formatMessage ensures the longMessage option is respected 1326 msg = self._formatMessage(msg, standardMsg) 1327 raise self.failureException(msg) 1328 1329 1330 def _deprecate(original_func): 1331 def deprecated_func(*args, **kwargs): 1332 warnings.warn( 1333 'Please use {0} instead.'.format(original_func.__name__), 1334 DeprecationWarning, 2) 1335 return original_func(*args, **kwargs) 1336 return deprecated_func 1337 1338 # see #9424 1339 failUnlessEqual = assertEquals = _deprecate(assertEqual) 1340 failIfEqual = assertNotEquals = _deprecate(assertNotEqual) 1341 failUnlessAlmostEqual = assertAlmostEquals = _deprecate(assertAlmostEqual) 1342 failIfAlmostEqual = assertNotAlmostEquals = _deprecate(assertNotAlmostEqual) 1343 failUnless = assert_ = _deprecate(assertTrue) 1344 failUnlessRaises = _deprecate(assertRaises) 1345 failIf = _deprecate(assertFalse) 1346 assertRaisesRegexp = _deprecate(assertRaisesRegex) 1347 assertRegexpMatches = _deprecate(assertRegex) 1348 assertNotRegexpMatches = _deprecate(assertNotRegex) 1349 1350 1351 1352class FunctionTestCase(TestCase): 1353 """A test case that wraps a test function. 1354 1355 This is useful for slipping pre-existing test functions into the 1356 unittest framework. Optionally, set-up and tidy-up functions can be 1357 supplied. As with TestCase, the tidy-up ('tearDown') function will 1358 always be called if the set-up ('setUp') function ran successfully. 1359 """ 1360 1361 def __init__(self, testFunc, setUp=None, tearDown=None, description=None): 1362 super(FunctionTestCase, self).__init__() 1363 self._setUpFunc = setUp 1364 self._tearDownFunc = tearDown 1365 self._testFunc = testFunc 1366 self._description = description 1367 1368 def setUp(self): 1369 if self._setUpFunc is not None: 1370 self._setUpFunc() 1371 1372 def tearDown(self): 1373 if self._tearDownFunc is not None: 1374 self._tearDownFunc() 1375 1376 def runTest(self): 1377 self._testFunc() 1378 1379 def id(self): 1380 return self._testFunc.__name__ 1381 1382 def __eq__(self, other): 1383 if not isinstance(other, self.__class__): 1384 return NotImplemented 1385 1386 return self._setUpFunc == other._setUpFunc and \ 1387 self._tearDownFunc == other._tearDownFunc and \ 1388 self._testFunc == other._testFunc and \ 1389 self._description == other._description 1390 1391 def __hash__(self): 1392 return hash((type(self), self._setUpFunc, self._tearDownFunc, 1393 self._testFunc, self._description)) 1394 1395 def __str__(self): 1396 return "%s (%s)" % (strclass(self.__class__), 1397 self._testFunc.__name__) 1398 1399 def __repr__(self): 1400 return "<%s tec=%s>" % (strclass(self.__class__), 1401 self._testFunc) 1402 1403 def shortDescription(self): 1404 if self._description is not None: 1405 return self._description 1406 doc = self._testFunc.__doc__ 1407 return doc and doc.split("\n")[0].strip() or None 1408 1409 1410class _SubTest(TestCase): 1411 1412 def __init__(self, test_case, message, params): 1413 super().__init__() 1414 self._message = message 1415 self.test_case = test_case 1416 self.params = params 1417 self.failureException = test_case.failureException 1418 1419 def runTest(self): 1420 raise NotImplementedError("subtests cannot be run directly") 1421 1422 def _subDescription(self): 1423 parts = [] 1424 if self._message is not _subtest_msg_sentinel: 1425 parts.append("[{}]".format(self._message)) 1426 if self.params: 1427 params_desc = ', '.join( 1428 "{}={!r}".format(k, v) 1429 for (k, v) in self.params.items()) 1430 parts.append("({})".format(params_desc)) 1431 return " ".join(parts) or '(<subtest>)' 1432 1433 def id(self): 1434 return "{} {}".format(self.test_case.id(), self._subDescription()) 1435 1436 def shortDescription(self): 1437 """Returns a one-line description of the subtest, or None if no 1438 description has been provided. 1439 """ 1440 return self.test_case.shortDescription() 1441 1442 def __str__(self): 1443 return "{} {}".format(self.test_case, self._subDescription()) 1444