1# Copyright (c) Twisted Matrix Laboratories. 2# See LICENSE for details. 3 4""" 5Tests for the behaviour of unit tests. 6 7Many tests in this module follow a simple pattern. A mixin is defined which 8includes test methods for a certain feature. The mixin is inherited from twice, 9once by a class also inheriting from SynchronousTestCase and once from a class 10inheriting from TestCase. These two subclasses are named like 11I{SynchronousFooTests} and I{AsynchronousFooTests}, where I{Foo} is related to 12the name of the mixin. Sometimes the mixin is defined in another module, along 13with the synchronous subclass. The mixin is imported into this module to define 14the asynchronous subclass. 15 16This pattern allows the same tests to be applied to the two base test case 17classes trial provides, ensuring their behavior is the same. 18 19Most new tests should be added in this pattern. Tests for functionality which 20is intentionally only provided by TestCase, not SynchronousTestCase, is excepted 21of course. 22""" 23 24 25import gc 26import sys 27import unittest as pyunit 28import weakref 29from io import StringIO 30 31from twisted.internet import defer, reactor 32from twisted.python.compat import _PYPY 33from twisted.python.reflect import namedAny 34from twisted.trial import reporter, runner, unittest, util 35from twisted.trial._asyncrunner import ( 36 _clearSuite, 37 _ForceGarbageCollectionDecorator, 38 _iterateTests, 39) 40from twisted.trial.test import erroneous 41from twisted.trial.test.test_suppression import SuppressionMixin 42 43 44class ResultsTestMixin: 45 """ 46 Provide useful APIs for test cases that are about test cases. 47 """ 48 49 def loadSuite(self, suite): 50 """ 51 Load tests from the given test case class and create a new reporter to 52 use for running it. 53 """ 54 self.loader = pyunit.TestLoader() 55 self.suite = self.loader.loadTestsFromTestCase(suite) 56 self.reporter = reporter.TestResult() 57 58 def test_setUp(self): 59 """ 60 test the setup 61 """ 62 self.assertTrue(self.reporter.wasSuccessful()) 63 self.assertEqual(self.reporter.errors, []) 64 self.assertEqual(self.reporter.failures, []) 65 self.assertEqual(self.reporter.skips, []) 66 67 def assertCount(self, numTests): 68 """ 69 Asserts that the test count is plausible 70 """ 71 self.assertEqual(self.suite.countTestCases(), numTests) 72 self.suite(self.reporter) 73 self.assertEqual(self.reporter.testsRun, numTests) 74 75 76class SuccessMixin: 77 """ 78 Tests for the reporting of successful tests in L{twisted.trial.unittest.TestCase}. 79 """ 80 81 def setUp(self): 82 """ 83 Setup our test case 84 """ 85 self.result = reporter.TestResult() 86 87 def test_successful(self): 88 """ 89 A successful test, used by other tests. 90 """ 91 92 def assertSuccessful(self, test, result): 93 """ 94 Utility function -- assert there is one success and the state is 95 plausible 96 """ 97 self.assertEqual(result.successes, 1) 98 self.assertEqual(result.failures, []) 99 self.assertEqual(result.errors, []) 100 self.assertEqual(result.expectedFailures, []) 101 self.assertEqual(result.unexpectedSuccesses, []) 102 self.assertEqual(result.skips, []) 103 104 def test_successfulIsReported(self): 105 """ 106 Test that when a successful test is run, it is reported as a success, 107 and not as any other kind of result. 108 """ 109 test = self.__class__("test_successful") 110 test.run(self.result) 111 self.assertSuccessful(test, self.result) 112 113 def test_defaultIsSuccessful(self): 114 """ 115 The test case type can be instantiated with no arguments, run, and 116 reported as being successful. 117 """ 118 test = self.__class__() 119 test.run(self.result) 120 self.assertSuccessful(test, self.result) 121 122 def test_noReference(self): 123 """ 124 Test that no reference is kept on a successful test. 125 """ 126 test = self.__class__("test_successful") 127 ref = weakref.ref(test) 128 test.run(self.result) 129 self.assertSuccessful(test, self.result) 130 del test 131 gc.collect() 132 self.assertIdentical(ref(), None) 133 134 135class SynchronousSuccessTests(SuccessMixin, unittest.SynchronousTestCase): 136 """ 137 Tests for the reporting of successful tests in the synchronous case. 138 """ 139 140 141class AsynchronousSuccessTests(SuccessMixin, unittest.TestCase): 142 """ 143 Tests for the reporting of successful tests in the synchronous case. 144 """ 145 146 147class SkipMethodsMixin(ResultsTestMixin): 148 """ 149 Tests for the reporting of skipping tests in L{twisted.trial.unittest.TestCase}. 150 """ 151 152 def setUp(self): 153 """ 154 Setup our test case 155 """ 156 self.loadSuite(self.Skipping) 157 158 def test_counting(self): 159 """ 160 Assert that there are three tests. 161 """ 162 self.assertCount(3) 163 164 def test_results(self): 165 """ 166 Running a suite in which all methods are individually set to skip 167 produces a successful result with no recorded errors or failures, all 168 the skipped methods recorded as skips, and no methods recorded as 169 successes. 170 """ 171 self.suite(self.reporter) 172 self.assertTrue(self.reporter.wasSuccessful()) 173 self.assertEqual(self.reporter.errors, []) 174 self.assertEqual(self.reporter.failures, []) 175 self.assertEqual(len(self.reporter.skips), 3) 176 self.assertEqual(self.reporter.successes, 0) 177 178 def test_setUp(self): 179 """ 180 Running a suite in which all methods are skipped by C{setUp} raising 181 L{SkipTest} produces a successful result with no recorded errors or 182 failures, all skipped methods recorded as skips, and no methods recorded 183 as successes. 184 """ 185 self.loadSuite(self.SkippingSetUp) 186 self.suite(self.reporter) 187 self.assertTrue(self.reporter.wasSuccessful()) 188 self.assertEqual(self.reporter.errors, []) 189 self.assertEqual(self.reporter.failures, []) 190 self.assertEqual(len(self.reporter.skips), 2) 191 self.assertEqual(self.reporter.successes, 0) 192 193 def test_reasons(self): 194 """ 195 Test that reasons work 196 """ 197 self.suite(self.reporter) 198 prefix = "test_" 199 # whiteboxing reporter 200 for test, reason in self.reporter.skips: 201 self.assertEqual(test.shortDescription()[len(prefix) :], str(reason)) 202 203 def test_deprecatedSkipWithoutReason(self): 204 """ 205 If a test method raises L{SkipTest} with no reason, a deprecation 206 warning is emitted. 207 """ 208 self.loadSuite(self.DeprecatedReasonlessSkip) 209 self.suite(self.reporter) 210 warnings = self.flushWarnings([self.DeprecatedReasonlessSkip.test_1]) 211 self.assertEqual(1, len(warnings)) 212 self.assertEqual(DeprecationWarning, warnings[0]["category"]) 213 self.assertEqual( 214 "Do not raise unittest.SkipTest with no arguments! Give a reason " 215 "for skipping tests!", 216 warnings[0]["message"], 217 ) 218 219 220class SynchronousSkipMethodTests(SkipMethodsMixin, unittest.SynchronousTestCase): 221 """ 222 Tests for the reporting of skipping tests in the synchronous case. 223 224 See: L{twisted.trial.test.test_tests.SkipMethodsMixin} 225 """ 226 227 Skipping = namedAny("twisted.trial.test.skipping.SynchronousSkipping") 228 SkippingSetUp = namedAny("twisted.trial.test.skipping.SynchronousSkippingSetUp") 229 DeprecatedReasonlessSkip = namedAny( 230 "twisted.trial.test.skipping.SynchronousDeprecatedReasonlessSkip" 231 ) 232 233 234class AsynchronousSkipMethodTests(SkipMethodsMixin, unittest.TestCase): 235 """ 236 Tests for the reporting of skipping tests in the asynchronous case. 237 238 See: L{twisted.trial.test.test_tests.SkipMethodsMixin} 239 """ 240 241 Skipping = namedAny("twisted.trial.test.skipping.AsynchronousSkipping") 242 SkippingSetUp = namedAny("twisted.trial.test.skipping.AsynchronousSkippingSetUp") 243 DeprecatedReasonlessSkip = namedAny( 244 "twisted.trial.test.skipping.AsynchronousDeprecatedReasonlessSkip" 245 ) 246 247 248class SkipClassesMixin(ResultsTestMixin): 249 """ 250 Test the class skipping features of L{twisted.trial.unittest.TestCase}. 251 """ 252 253 def setUp(self): 254 """ 255 Setup our test case 256 """ 257 self.loadSuite(self.SkippedClass) 258 self.SkippedClass._setUpRan = False 259 260 def test_counting(self): 261 """ 262 Skipped test methods still contribute to the total test count. 263 """ 264 self.assertCount(4) 265 266 def test_setUpRan(self): 267 """ 268 The C{setUp} method is not called if the class is set to skip. 269 """ 270 self.suite(self.reporter) 271 self.assertFalse(self.SkippedClass._setUpRan) 272 273 def test_results(self): 274 """ 275 Skipped test methods don't cause C{wasSuccessful} to return C{False}, 276 nor do they contribute to the C{errors} or C{failures} of the reporter, 277 or to the count of successes. They do, however, add elements to the 278 reporter's C{skips} list. 279 """ 280 self.suite(self.reporter) 281 self.assertTrue(self.reporter.wasSuccessful()) 282 self.assertEqual(self.reporter.errors, []) 283 self.assertEqual(self.reporter.failures, []) 284 self.assertEqual(len(self.reporter.skips), 4) 285 self.assertEqual(self.reporter.successes, 0) 286 287 def test_reasons(self): 288 """ 289 Test methods which raise L{unittest.SkipTest} or have their C{skip} 290 attribute set to something are skipped. 291 """ 292 self.suite(self.reporter) 293 expectedReasons = ["class", "skip2", "class", "class"] 294 # whitebox reporter 295 reasonsGiven = [reason for test, reason in self.reporter.skips] 296 self.assertEqual(expectedReasons, reasonsGiven) 297 298 299class SynchronousSkipClassTests(SkipClassesMixin, unittest.SynchronousTestCase): 300 """ 301 Test the class skipping features in the synchronous case. 302 303 See: L{twisted.trial.test.test_tests.SkipClassesMixin} 304 """ 305 306 SkippedClass = namedAny("twisted.trial.test.skipping.SynchronousSkippedClass") 307 308 309class AsynchronousSkipClassTests(SkipClassesMixin, unittest.TestCase): 310 """ 311 Test the class skipping features in the asynchronous case. 312 313 See: L{twisted.trial.test.test_tests.SkipClassesMixin} 314 """ 315 316 SkippedClass = namedAny("twisted.trial.test.skipping.AsynchronousSkippedClass") 317 318 319class TodoMixin(ResultsTestMixin): 320 """ 321 Tests for the individual test method I{expected failure} features of 322 L{twisted.trial.unittest.TestCase}. 323 """ 324 325 def setUp(self): 326 """ 327 Setup our test case 328 """ 329 self.loadSuite(self.Todo) 330 331 def test_counting(self): 332 """ 333 Ensure that we've got three test cases. 334 """ 335 self.assertCount(3) 336 337 def test_results(self): 338 """ 339 Running a suite in which all methods are individually marked as expected 340 to fail produces a successful result with no recorded errors, failures, 341 or skips, all methods which fail and were expected to fail recorded as 342 C{expectedFailures}, and all methods which pass but which were expected 343 to fail recorded as C{unexpectedSuccesses}. Additionally, no tests are 344 recorded as successes. 345 """ 346 self.suite(self.reporter) 347 self.assertTrue(self.reporter.wasSuccessful()) 348 self.assertEqual(self.reporter.errors, []) 349 self.assertEqual(self.reporter.failures, []) 350 self.assertEqual(self.reporter.skips, []) 351 self.assertEqual(len(self.reporter.expectedFailures), 2) 352 self.assertEqual(len(self.reporter.unexpectedSuccesses), 1) 353 self.assertEqual(self.reporter.successes, 0) 354 355 def test_expectedFailures(self): 356 """ 357 Ensure that expected failures are handled properly. 358 """ 359 self.suite(self.reporter) 360 expectedReasons = ["todo1", "todo2"] 361 reasonsGiven = [r.reason for t, e, r in self.reporter.expectedFailures] 362 self.assertEqual(expectedReasons, reasonsGiven) 363 364 def test_unexpectedSuccesses(self): 365 """ 366 Ensure that unexpected successes are caught. 367 """ 368 self.suite(self.reporter) 369 expectedReasons = ["todo3"] 370 reasonsGiven = [r.reason for t, r in self.reporter.unexpectedSuccesses] 371 self.assertEqual(expectedReasons, reasonsGiven) 372 373 def test_expectedSetUpFailure(self): 374 """ 375 C{setUp} is excluded from the failure expectation defined by a C{todo} 376 attribute on a test method. 377 """ 378 self.loadSuite(self.SetUpTodo) 379 self.suite(self.reporter) 380 self.assertFalse(self.reporter.wasSuccessful()) 381 self.assertEqual(len(self.reporter.errors), 1) 382 self.assertEqual(self.reporter.failures, []) 383 self.assertEqual(self.reporter.skips, []) 384 self.assertEqual(len(self.reporter.expectedFailures), 0) 385 self.assertEqual(len(self.reporter.unexpectedSuccesses), 0) 386 self.assertEqual(self.reporter.successes, 0) 387 388 def test_expectedTearDownFailure(self): 389 """ 390 C{tearDown} is excluded from the failure expectation defined by a C{todo} 391 attribute on a test method. 392 """ 393 self.loadSuite(self.TearDownTodo) 394 self.suite(self.reporter) 395 self.assertFalse(self.reporter.wasSuccessful()) 396 self.assertEqual(len(self.reporter.errors), 1) 397 self.assertEqual(self.reporter.failures, []) 398 self.assertEqual(self.reporter.skips, []) 399 self.assertEqual(len(self.reporter.expectedFailures), 0) 400 # This seems strange, since tearDown raised an exception. However, the 401 # test method did complete without error. The tearDown error is 402 # reflected in the errors list, checked above. 403 self.assertEqual(len(self.reporter.unexpectedSuccesses), 1) 404 self.assertEqual(self.reporter.successes, 0) 405 406 407class SynchronousTodoTests(TodoMixin, unittest.SynchronousTestCase): 408 """ 409 Test the class skipping features in the synchronous case. 410 411 See: L{twisted.trial.test.test_tests.TodoMixin} 412 """ 413 414 Todo = namedAny("twisted.trial.test.skipping.SynchronousTodo") 415 SetUpTodo = namedAny("twisted.trial.test.skipping.SynchronousSetUpTodo") 416 TearDownTodo = namedAny("twisted.trial.test.skipping.SynchronousTearDownTodo") 417 418 419class AsynchronousTodoTests(TodoMixin, unittest.TestCase): 420 """ 421 Test the class skipping features in the asynchronous case. 422 423 See: L{twisted.trial.test.test_tests.TodoMixin} 424 """ 425 426 Todo = namedAny("twisted.trial.test.skipping.AsynchronousTodo") 427 SetUpTodo = namedAny("twisted.trial.test.skipping.AsynchronousSetUpTodo") 428 TearDownTodo = namedAny("twisted.trial.test.skipping.AsynchronousTearDownTodo") 429 430 431class ClassTodoMixin(ResultsTestMixin): 432 """ 433 Tests for the class-wide I{expected failure} features of 434 L{twisted.trial.unittest.TestCase}. 435 """ 436 437 def setUp(self): 438 """ 439 Setup our test case 440 """ 441 self.loadSuite(self.TodoClass) 442 443 def test_counting(self): 444 """ 445 Ensure that we've got four test cases. 446 """ 447 self.assertCount(4) 448 449 def test_results(self): 450 """ 451 Running a suite in which an entire class is marked as expected to fail 452 produces a successful result with no recorded errors, failures, or 453 skips, all methods which fail and were expected to fail recorded as 454 C{expectedFailures}, and all methods which pass but which were expected 455 to fail recorded as C{unexpectedSuccesses}. Additionally, no tests are 456 recorded as successes. 457 """ 458 self.suite(self.reporter) 459 self.assertTrue(self.reporter.wasSuccessful()) 460 self.assertEqual(self.reporter.errors, []) 461 self.assertEqual(self.reporter.failures, []) 462 self.assertEqual(self.reporter.skips, []) 463 self.assertEqual(len(self.reporter.expectedFailures), 2) 464 self.assertEqual(len(self.reporter.unexpectedSuccesses), 2) 465 self.assertEqual(self.reporter.successes, 0) 466 467 def test_expectedFailures(self): 468 """ 469 Ensure that expected failures are handled properly. 470 """ 471 self.suite(self.reporter) 472 expectedReasons = ["method", "class"] 473 reasonsGiven = [r.reason for t, e, r in self.reporter.expectedFailures] 474 self.assertEqual(expectedReasons, reasonsGiven) 475 476 def test_unexpectedSuccesses(self): 477 """ 478 Ensure that unexpected successes are caught. 479 """ 480 self.suite(self.reporter) 481 expectedReasons = ["method", "class"] 482 reasonsGiven = [r.reason for t, r in self.reporter.unexpectedSuccesses] 483 self.assertEqual(expectedReasons, reasonsGiven) 484 485 486class SynchronousClassTodoTests(ClassTodoMixin, unittest.SynchronousTestCase): 487 """ 488 Tests for the class-wide I{expected failure} features in the synchronous case. 489 490 See: L{twisted.trial.test.test_tests.ClassTodoMixin} 491 """ 492 493 TodoClass = namedAny("twisted.trial.test.skipping.SynchronousTodoClass") 494 495 496class AsynchronousClassTodoTests(ClassTodoMixin, unittest.TestCase): 497 """ 498 Tests for the class-wide I{expected failure} features in the asynchronous case. 499 500 See: L{twisted.trial.test.test_tests.ClassTodoMixin} 501 """ 502 503 TodoClass = namedAny("twisted.trial.test.skipping.AsynchronousTodoClass") 504 505 506class StrictTodoMixin(ResultsTestMixin): 507 """ 508 Tests for the I{expected failure} features of 509 L{twisted.trial.unittest.TestCase} in which the exact failure which is 510 expected is indicated. 511 """ 512 513 def setUp(self): 514 """ 515 Setup our test case 516 """ 517 self.loadSuite(self.StrictTodo) 518 519 def test_counting(self): 520 """ 521 Assert there are seven test cases 522 """ 523 self.assertCount(7) 524 525 def test_results(self): 526 """ 527 A test method which is marked as expected to fail with a particular 528 exception is only counted as an expected failure if it does fail with 529 that exception, not if it fails with some other exception. 530 """ 531 self.suite(self.reporter) 532 self.assertFalse(self.reporter.wasSuccessful()) 533 self.assertEqual(len(self.reporter.errors), 2) 534 self.assertEqual(len(self.reporter.failures), 1) 535 self.assertEqual(len(self.reporter.expectedFailures), 3) 536 self.assertEqual(len(self.reporter.unexpectedSuccesses), 1) 537 self.assertEqual(self.reporter.successes, 0) 538 self.assertEqual(self.reporter.skips, []) 539 540 def test_expectedFailures(self): 541 """ 542 Ensure that expected failures are handled properly. 543 """ 544 self.suite(self.reporter) 545 expectedReasons = ["todo1", "todo2", "todo5"] 546 reasonsGotten = [r.reason for t, e, r in self.reporter.expectedFailures] 547 self.assertEqual(expectedReasons, reasonsGotten) 548 549 def test_unexpectedSuccesses(self): 550 """ 551 Ensure that unexpected successes are caught. 552 """ 553 self.suite(self.reporter) 554 expectedReasons = [([RuntimeError], "todo7")] 555 reasonsGotten = [ 556 (r.errors, r.reason) for t, r in self.reporter.unexpectedSuccesses 557 ] 558 self.assertEqual(expectedReasons, reasonsGotten) 559 560 561class SynchronousStrictTodoTests(StrictTodoMixin, unittest.SynchronousTestCase): 562 """ 563 Tests for the expected failure case when the exact failure that is expected 564 is indicated in the synchronous case 565 566 See: L{twisted.trial.test.test_tests.StrictTodoMixin} 567 """ 568 569 StrictTodo = namedAny("twisted.trial.test.skipping.SynchronousStrictTodo") 570 571 572class AsynchronousStrictTodoTests(StrictTodoMixin, unittest.TestCase): 573 """ 574 Tests for the expected failure case when the exact failure that is expected 575 is indicated in the asynchronous case 576 577 See: L{twisted.trial.test.test_tests.StrictTodoMixin} 578 """ 579 580 StrictTodo = namedAny("twisted.trial.test.skipping.AsynchronousStrictTodo") 581 582 583class ReactorCleanupTests(unittest.SynchronousTestCase): 584 """ 585 Tests for cleanup and reporting of reactor event sources left behind by test 586 methods. 587 """ 588 589 def setUp(self): 590 """ 591 Setup our test case 592 """ 593 self.result = reporter.Reporter(StringIO()) 594 self.loader = runner.TestLoader() 595 596 def test_leftoverSockets(self): 597 """ 598 Trial reports a L{util.DirtyReactorAggregateError} if a test leaves 599 sockets behind. 600 """ 601 suite = self.loader.loadByName( 602 "twisted.trial.test.erroneous.SocketOpenTest.test_socketsLeftOpen" 603 ) 604 suite.run(self.result) 605 self.assertFalse(self.result.wasSuccessful()) 606 # socket cleanup happens at end of class's tests. 607 # all the tests in the class are successful, even if the suite 608 # fails 609 self.assertEqual(self.result.successes, 1) 610 failure = self.result.errors[0][1] 611 self.assertTrue(failure.check(util.DirtyReactorAggregateError)) 612 613 def test_leftoverPendingCalls(self): 614 """ 615 Trial reports a L{util.DirtyReactorAggregateError} and fails the test 616 if a test leaves a L{DelayedCall} hanging. 617 """ 618 suite = erroneous.ReactorCleanupTests("test_leftoverPendingCalls") 619 suite.run(self.result) 620 self.assertFalse(self.result.wasSuccessful()) 621 failure = self.result.errors[0][1] 622 self.assertEqual(self.result.successes, 0) 623 self.assertTrue(failure.check(util.DirtyReactorAggregateError)) 624 625 626class FixtureMixin: 627 """ 628 Tests for fixture helper methods (e.g. setUp, tearDown). 629 """ 630 631 def setUp(self): 632 """ 633 Setup our test case 634 """ 635 self.reporter = reporter.Reporter() 636 self.loader = pyunit.TestLoader() 637 638 def test_brokenSetUp(self): 639 """ 640 When setUp fails, the error is recorded in the result object. 641 """ 642 suite = self.loader.loadTestsFromTestCase(self.TestFailureInSetUp) 643 suite.run(self.reporter) 644 self.assertTrue(len(self.reporter.errors) > 0) 645 self.assertIsInstance(self.reporter.errors[0][1].value, erroneous.FoolishError) 646 self.assertEqual(0, self.reporter.successes) 647 648 def test_brokenTearDown(self): 649 """ 650 When tearDown fails, the error is recorded in the result object. 651 """ 652 suite = self.loader.loadTestsFromTestCase(self.TestFailureInTearDown) 653 suite.run(self.reporter) 654 errors = self.reporter.errors 655 self.assertTrue(len(errors) > 0) 656 self.assertIsInstance(errors[0][1].value, erroneous.FoolishError) 657 self.assertEqual(0, self.reporter.successes) 658 659 def test_tearDownRunsOnTestFailure(self): 660 """ 661 L{SynchronousTestCase.tearDown} runs when a test method fails. 662 """ 663 suite = self.loader.loadTestsFromTestCase(self.TestFailureButTearDownRuns) 664 665 case = list(suite)[0] 666 self.assertFalse(case.tornDown) 667 668 suite.run(self.reporter) 669 errors = self.reporter.errors 670 self.assertTrue(len(errors) > 0) 671 self.assertIsInstance(errors[0][1].value, erroneous.FoolishError) 672 self.assertEqual(0, self.reporter.successes) 673 674 self.assertTrue(case.tornDown) 675 676 677class SynchronousFixtureTests(FixtureMixin, unittest.SynchronousTestCase): 678 """ 679 Tests for broken fixture helper methods in the synchronous case 680 681 See: L{twisted.trial.test.test_tests.FixtureMixin} 682 """ 683 684 TestFailureInSetUp = namedAny( 685 "twisted.trial.test.erroneous.SynchronousTestFailureInSetUp" 686 ) 687 TestFailureInTearDown = namedAny( 688 "twisted.trial.test.erroneous.SynchronousTestFailureInTearDown" 689 ) 690 TestFailureButTearDownRuns = namedAny( 691 "twisted.trial.test.erroneous.SynchronousTestFailureButTearDownRuns" 692 ) 693 694 695class AsynchronousFixtureTests(FixtureMixin, unittest.TestCase): 696 """ 697 Tests for broken fixture helper methods in the asynchronous case 698 699 See: L{twisted.trial.test.test_tests.FixtureMixin} 700 """ 701 702 TestFailureInSetUp = namedAny( 703 "twisted.trial.test.erroneous.AsynchronousTestFailureInSetUp" 704 ) 705 TestFailureInTearDown = namedAny( 706 "twisted.trial.test.erroneous.AsynchronousTestFailureInTearDown" 707 ) 708 TestFailureButTearDownRuns = namedAny( 709 "twisted.trial.test.erroneous.AsynchronousTestFailureButTearDownRuns" 710 ) 711 712 713class AsynchronousSuppressionTests(SuppressionMixin, unittest.TestCase): 714 """ 715 Tests for the warning suppression features of 716 L{twisted.trial.unittest.TestCase} 717 718 See L{twisted.trial.test.test_suppression.SuppressionMixin} 719 """ 720 721 TestSetUpSuppression = namedAny( 722 "twisted.trial.test.suppression.AsynchronousTestSetUpSuppression" 723 ) 724 TestTearDownSuppression = namedAny( 725 "twisted.trial.test.suppression.AsynchronousTestTearDownSuppression" 726 ) 727 TestSuppression = namedAny( 728 "twisted.trial.test.suppression.AsynchronousTestSuppression" 729 ) 730 TestSuppression2 = namedAny( 731 "twisted.trial.test.suppression.AsynchronousTestSuppression2" 732 ) 733 734 735class GCMixin: 736 """ 737 I provide a few mock tests that log setUp, tearDown, test execution and 738 garbage collection. I'm used to test whether gc.collect gets called. 739 """ 740 741 class BasicTest(unittest.SynchronousTestCase): 742 """ 743 Mock test to run. 744 """ 745 746 def setUp(self): 747 """ 748 Mock setUp 749 """ 750 self._log("setUp") 751 752 def test_foo(self): 753 """ 754 Mock test case 755 """ 756 self._log("test") 757 758 def tearDown(self): 759 """ 760 Mock tear tearDown 761 """ 762 self._log("tearDown") 763 764 def _log(self, msg): 765 """ 766 Log function 767 """ 768 self._collectCalled.append(msg) 769 770 def collect(self): 771 """Fake gc.collect""" 772 self._log("collect") 773 774 def setUp(self): 775 """ 776 Setup our test case 777 """ 778 self._collectCalled = [] 779 self.BasicTest._log = self._log 780 self._oldCollect = gc.collect 781 gc.collect = self.collect 782 783 def tearDown(self): 784 """ 785 Tear down the test 786 """ 787 gc.collect = self._oldCollect 788 789 790class GarbageCollectionDefaultTests(GCMixin, unittest.SynchronousTestCase): 791 """ 792 By default, tests should not force garbage collection. 793 """ 794 795 def test_collectNotDefault(self): 796 """ 797 By default, tests should not force garbage collection. 798 """ 799 test = self.BasicTest("test_foo") 800 result = reporter.TestResult() 801 test.run(result) 802 self.assertEqual(self._collectCalled, ["setUp", "test", "tearDown"]) 803 804 805class GarbageCollectionTests(GCMixin, unittest.SynchronousTestCase): 806 """ 807 Test that, when force GC, it works. 808 """ 809 810 def test_collectCalled(self): 811 """ 812 test gc.collect is called before and after each test. 813 """ 814 test = GarbageCollectionTests.BasicTest("test_foo") 815 test = _ForceGarbageCollectionDecorator(test) 816 result = reporter.TestResult() 817 test.run(result) 818 self.assertEqual( 819 self._collectCalled, ["collect", "setUp", "test", "tearDown", "collect"] 820 ) 821 822 823class UnhandledDeferredTests(unittest.SynchronousTestCase): 824 """ 825 Test what happens when we have an unhandled deferred left around after 826 a test. 827 """ 828 829 def setUp(self): 830 """ 831 Setup our test case 832 """ 833 from twisted.trial.test import weird 834 835 # test_unhandledDeferred creates a cycle. we need explicit control of gc 836 gc.disable() 837 self.test1 = _ForceGarbageCollectionDecorator( 838 weird.TestBleeding("test_unhandledDeferred") 839 ) 840 841 def test_isReported(self): 842 """ 843 Forcing garbage collection should cause unhandled Deferreds to be 844 reported as errors. 845 """ 846 result = reporter.TestResult() 847 self.test1(result) 848 self.assertEqual( 849 len(result.errors), 1, "Unhandled deferred passed without notice" 850 ) 851 852 @pyunit.skipIf(_PYPY, "GC works differently on PyPy.") 853 def test_doesntBleed(self): 854 """ 855 Forcing garbage collection in the test should mean that there are 856 no unreachable cycles immediately after the test completes. 857 """ 858 result = reporter.TestResult() 859 self.test1(result) 860 self.flushLoggedErrors() # test1 logs errors that get caught be us. 861 # test1 created unreachable cycle. 862 # it & all others should have been collected by now. 863 n = len(gc.garbage) 864 self.assertEqual(n, 0, "unreachable cycle still existed") 865 # check that last gc.collect didn't log more errors 866 x = self.flushLoggedErrors() 867 self.assertEqual(len(x), 0, "Errors logged after gc.collect") 868 869 def tearDown(self): 870 """ 871 Tear down the test 872 """ 873 gc.collect() 874 gc.enable() 875 self.flushLoggedErrors() 876 877 878class AddCleanupMixin: 879 """ 880 Test the addCleanup method of TestCase. 881 """ 882 883 def setUp(self): 884 """ 885 Setup our test case 886 """ 887 super().setUp() 888 self.result = reporter.TestResult() 889 self.test = self.AddCleanup() 890 891 def test_addCleanupCalledIfSetUpFails(self): 892 """ 893 Callables added with C{addCleanup} are run even if setUp fails. 894 """ 895 self.test.setUp = self.test.brokenSetUp 896 self.test.addCleanup(self.test.append, "foo") 897 self.test.run(self.result) 898 self.assertEqual(["setUp", "foo"], self.test.log) 899 900 def test_addCleanupCalledIfSetUpSkips(self): 901 """ 902 Callables added with C{addCleanup} are run even if setUp raises 903 L{SkipTest}. This allows test authors to reliably provide clean up 904 code using C{addCleanup}. 905 """ 906 self.test.setUp = self.test.skippingSetUp 907 self.test.addCleanup(self.test.append, "foo") 908 self.test.run(self.result) 909 self.assertEqual(["setUp", "foo"], self.test.log) 910 911 def test_addCleanupCalledInReverseOrder(self): 912 """ 913 Callables added with C{addCleanup} should be called before C{tearDown} 914 in reverse order of addition. 915 """ 916 self.test.addCleanup(self.test.append, "foo") 917 self.test.addCleanup(self.test.append, "bar") 918 self.test.run(self.result) 919 self.assertEqual(["setUp", "runTest", "bar", "foo", "tearDown"], self.test.log) 920 921 def test_errorInCleanupIsCaptured(self): 922 """ 923 Errors raised in cleanup functions should be treated like errors in 924 C{tearDown}. They should be added as errors and fail the test. Skips, 925 todos and failures are all treated as errors. 926 """ 927 self.test.addCleanup(self.test.fail, "foo") 928 self.test.run(self.result) 929 self.assertFalse(self.result.wasSuccessful()) 930 self.assertEqual(1, len(self.result.errors)) 931 [(test, error)] = self.result.errors 932 self.assertEqual(test, self.test) 933 self.assertEqual(error.getErrorMessage(), "foo") 934 935 def test_cleanupsContinueRunningAfterError(self): 936 """ 937 If a cleanup raises an error then that does not stop the other 938 cleanups from being run. 939 """ 940 self.test.addCleanup(self.test.append, "foo") 941 self.test.addCleanup(self.test.fail, "bar") 942 self.test.run(self.result) 943 self.assertEqual(["setUp", "runTest", "foo", "tearDown"], self.test.log) 944 self.assertEqual(1, len(self.result.errors)) 945 [(test, error)] = self.result.errors 946 self.assertEqual(test, self.test) 947 self.assertEqual(error.getErrorMessage(), "bar") 948 949 def test_multipleErrorsReported(self): 950 """ 951 If more than one cleanup fails, then the test should fail with more 952 than one error. 953 """ 954 self.test.addCleanup(self.test.fail, "foo") 955 self.test.addCleanup(self.test.fail, "bar") 956 self.test.run(self.result) 957 self.assertEqual(["setUp", "runTest", "tearDown"], self.test.log) 958 self.assertEqual(2, len(self.result.errors)) 959 [(test1, error1), (test2, error2)] = self.result.errors 960 self.assertEqual(test1, self.test) 961 self.assertEqual(test2, self.test) 962 self.assertEqual(error1.getErrorMessage(), "bar") 963 self.assertEqual(error2.getErrorMessage(), "foo") 964 965 966class SynchronousAddCleanupTests(AddCleanupMixin, unittest.SynchronousTestCase): 967 """ 968 Test the addCleanup method of TestCase in the synchronous case 969 970 See: L{twisted.trial.test.test_tests.AddCleanupMixin} 971 """ 972 973 AddCleanup = namedAny("twisted.trial.test.skipping.SynchronousAddCleanup") 974 975 976class AsynchronousAddCleanupTests(AddCleanupMixin, unittest.TestCase): 977 """ 978 Test the addCleanup method of TestCase in the asynchronous case 979 980 See: L{twisted.trial.test.test_tests.AddCleanupMixin} 981 """ 982 983 AddCleanup = namedAny("twisted.trial.test.skipping.AsynchronousAddCleanup") 984 985 def test_addCleanupWaitsForDeferreds(self): 986 """ 987 If an added callable returns a L{Deferred}, then the test should wait 988 until that L{Deferred} has fired before running the next cleanup 989 method. 990 """ 991 992 def cleanup(message): 993 d = defer.Deferred() 994 reactor.callLater(0, d.callback, message) 995 return d.addCallback(self.test.append) 996 997 self.test.addCleanup(self.test.append, "foo") 998 self.test.addCleanup(cleanup, "bar") 999 self.test.run(self.result) 1000 self.assertEqual(["setUp", "runTest", "bar", "foo", "tearDown"], self.test.log) 1001 1002 1003class SuiteClearingMixin: 1004 """ 1005 Tests for our extension that allows us to clear out a L{TestSuite}. 1006 """ 1007 1008 def test_clearSuite(self): 1009 """ 1010 Calling L{_clearSuite} on a populated L{TestSuite} removes 1011 all tests. 1012 """ 1013 suite = unittest.TestSuite() 1014 suite.addTest(self.TestCase()) 1015 # Double check that the test suite actually has something in it. 1016 self.assertEqual(1, suite.countTestCases()) 1017 _clearSuite(suite) 1018 self.assertEqual(0, suite.countTestCases()) 1019 1020 def test_clearPyunitSuite(self): 1021 """ 1022 Calling L{_clearSuite} on a populated standard library 1023 L{TestSuite} removes all tests. 1024 1025 This test is important since C{_clearSuite} operates by mutating 1026 internal variables. 1027 """ 1028 suite = pyunit.TestSuite() 1029 suite.addTest(self.TestCase()) 1030 # Double check that the test suite actually has something in it. 1031 self.assertEqual(1, suite.countTestCases()) 1032 _clearSuite(suite) 1033 self.assertEqual(0, suite.countTestCases()) 1034 1035 1036class SynchronousSuiteClearingTests(SuiteClearingMixin, unittest.SynchronousTestCase): 1037 """ 1038 Tests for our extension that allows us to clear out a L{TestSuite} in the 1039 synchronous case. 1040 1041 See L{twisted.trial.test.test_tests.SuiteClearingMixin} 1042 """ 1043 1044 TestCase = unittest.SynchronousTestCase 1045 1046 1047class AsynchronousSuiteClearingTests(SuiteClearingMixin, unittest.TestCase): 1048 """ 1049 Tests for our extension that allows us to clear out a L{TestSuite} in the 1050 asynchronous case. 1051 1052 See L{twisted.trial.test.test_tests.SuiteClearingMixin} 1053 """ 1054 1055 TestCase = unittest.TestCase 1056 1057 1058class TestDecoratorMixin: 1059 """ 1060 Tests for our test decoration features. 1061 """ 1062 1063 def assertTestsEqual(self, observed, expected): 1064 """ 1065 Assert that the given decorated tests are equal. 1066 """ 1067 self.assertEqual(observed.__class__, expected.__class__, "Different class") 1068 observedOriginal = getattr(observed, "_originalTest", None) 1069 expectedOriginal = getattr(expected, "_originalTest", None) 1070 self.assertIdentical(observedOriginal, expectedOriginal) 1071 if observedOriginal is expectedOriginal is None: 1072 self.assertIdentical(observed, expected) 1073 1074 def assertSuitesEqual(self, observed, expected): 1075 """ 1076 Assert that the given test suites with decorated tests are equal. 1077 """ 1078 self.assertEqual(observed.__class__, expected.__class__, "Different class") 1079 self.assertEqual( 1080 len(observed._tests), len(expected._tests), "Different number of tests." 1081 ) 1082 for observedTest, expectedTest in zip(observed._tests, expected._tests): 1083 if getattr(observedTest, "_tests", None) is not None: 1084 self.assertSuitesEqual(observedTest, expectedTest) 1085 else: 1086 self.assertTestsEqual(observedTest, expectedTest) 1087 1088 def test_usesAdaptedReporterWithRun(self): 1089 """ 1090 For decorated tests, C{run} uses a result adapter that preserves the 1091 test decoration for calls to C{addError}, C{startTest} and the like. 1092 1093 See L{reporter._AdaptedReporter}. 1094 """ 1095 test = self.TestCase() 1096 decoratedTest = unittest.TestDecorator(test) 1097 # Move to top in ticket #5964: 1098 from twisted.trial.test.test_reporter import LoggingReporter 1099 1100 result = LoggingReporter() 1101 decoratedTest.run(result) 1102 self.assertTestsEqual(result.test, decoratedTest) 1103 1104 def test_usesAdaptedReporterWithCall(self): 1105 """ 1106 For decorated tests, C{__call__} uses a result adapter that preserves 1107 the test decoration for calls to C{addError}, C{startTest} and the 1108 like. 1109 1110 See L{reporter._AdaptedReporter}. 1111 """ 1112 test = self.TestCase() 1113 decoratedTest = unittest.TestDecorator(test) 1114 # Move to top in ticket #5964: 1115 from twisted.trial.test.test_reporter import LoggingReporter 1116 1117 result = LoggingReporter() 1118 decoratedTest(result) 1119 self.assertTestsEqual(result.test, decoratedTest) 1120 1121 def test_decorateSingleTest(self): 1122 """ 1123 Calling L{decorate} on a single test case returns the test case 1124 decorated with the provided decorator. 1125 """ 1126 test = self.TestCase() 1127 decoratedTest = unittest.decorate(test, unittest.TestDecorator) 1128 self.assertTestsEqual(unittest.TestDecorator(test), decoratedTest) 1129 1130 def test_decorateTestSuite(self): 1131 """ 1132 Calling L{decorate} on a test suite will return a test suite with 1133 each test decorated with the provided decorator. 1134 """ 1135 test = self.TestCase() 1136 suite = unittest.TestSuite([test]) 1137 decoratedTest = unittest.decorate(suite, unittest.TestDecorator) 1138 self.assertSuitesEqual( 1139 decoratedTest, unittest.TestSuite([unittest.TestDecorator(test)]) 1140 ) 1141 1142 def test_decorateInPlaceMutatesOriginal(self): 1143 """ 1144 Calling L{decorate} on a test suite will mutate the original suite. 1145 """ 1146 test = self.TestCase() 1147 suite = unittest.TestSuite([test]) 1148 decoratedTest = unittest.decorate(suite, unittest.TestDecorator) 1149 self.assertSuitesEqual( 1150 decoratedTest, unittest.TestSuite([unittest.TestDecorator(test)]) 1151 ) 1152 self.assertSuitesEqual( 1153 suite, unittest.TestSuite([unittest.TestDecorator(test)]) 1154 ) 1155 1156 def test_decorateTestSuiteReferences(self): 1157 """ 1158 When decorating a test suite in-place, the number of references to the 1159 test objects in that test suite should stay the same. 1160 1161 Previously, L{unittest.decorate} recreated a test suite, so the 1162 original suite kept references to the test objects. This test is here 1163 to ensure the problem doesn't reappear again. 1164 """ 1165 getrefcount = getattr(sys, "getrefcount", None) 1166 if getrefcount is None: 1167 # For example non CPython like _PYPY. 1168 raise unittest.SkipTest("getrefcount not supported on this platform") 1169 test = self.TestCase() 1170 suite = unittest.TestSuite([test]) 1171 count1 = getrefcount(test) 1172 unittest.decorate(suite, unittest.TestDecorator) 1173 count2 = getrefcount(test) 1174 self.assertEqual(count1, count2) 1175 1176 def test_decorateNestedTestSuite(self): 1177 """ 1178 Calling L{decorate} on a test suite with nested suites will return a 1179 test suite that maintains the same structure, but with all tests 1180 decorated. 1181 """ 1182 test = self.TestCase() 1183 suite = unittest.TestSuite([unittest.TestSuite([test])]) 1184 decoratedTest = unittest.decorate(suite, unittest.TestDecorator) 1185 expected = unittest.TestSuite( 1186 [unittest.TestSuite([unittest.TestDecorator(test)])] 1187 ) 1188 self.assertSuitesEqual(decoratedTest, expected) 1189 1190 def test_decorateDecoratedSuite(self): 1191 """ 1192 Calling L{decorate} on a test suite with already-decorated tests 1193 decorates all of the tests in the suite again. 1194 """ 1195 test = self.TestCase() 1196 decoratedTest = unittest.decorate(test, unittest.TestDecorator) 1197 redecoratedTest = unittest.decorate(decoratedTest, unittest.TestDecorator) 1198 self.assertTestsEqual(redecoratedTest, unittest.TestDecorator(decoratedTest)) 1199 1200 def test_decoratePreservesSuite(self): 1201 """ 1202 Tests can be in non-standard suites. L{decorate} preserves the 1203 non-standard suites when it decorates the tests. 1204 """ 1205 test = self.TestCase() 1206 suite = runner.DestructiveTestSuite([test]) 1207 decorated = unittest.decorate(suite, unittest.TestDecorator) 1208 self.assertSuitesEqual( 1209 decorated, runner.DestructiveTestSuite([unittest.TestDecorator(test)]) 1210 ) 1211 1212 1213class SynchronousTestDecoratorTests(TestDecoratorMixin, unittest.SynchronousTestCase): 1214 """ 1215 Tests for our test decoration features in the synchronous case. 1216 1217 See L{twisted.trial.test.test_tests.TestDecoratorMixin} 1218 """ 1219 1220 TestCase = unittest.SynchronousTestCase 1221 1222 1223class AsynchronousTestDecoratorTests(TestDecoratorMixin, unittest.TestCase): 1224 """ 1225 Tests for our test decoration features in the asynchronous case. 1226 1227 See L{twisted.trial.test.test_tests.TestDecoratorMixin} 1228 """ 1229 1230 TestCase = unittest.TestCase 1231 1232 1233class MonkeyPatchMixin: 1234 """ 1235 Tests for the patch() helper method in L{unittest.TestCase}. 1236 """ 1237 1238 def setUp(self): 1239 """ 1240 Setup our test case 1241 """ 1242 self.originalValue = "original" 1243 self.patchedValue = "patched" 1244 self.objectToPatch = self.originalValue 1245 self.test = self.TestCase() 1246 1247 def test_patch(self): 1248 """ 1249 Calling C{patch()} on a test monkey patches the specified object and 1250 attribute. 1251 """ 1252 self.test.patch(self, "objectToPatch", self.patchedValue) 1253 self.assertEqual(self.objectToPatch, self.patchedValue) 1254 1255 def test_patchRestoredAfterRun(self): 1256 """ 1257 Any monkey patches introduced by a test using C{patch()} are reverted 1258 after the test has run. 1259 """ 1260 self.test.patch(self, "objectToPatch", self.patchedValue) 1261 self.test.run(reporter.Reporter()) 1262 self.assertEqual(self.objectToPatch, self.originalValue) 1263 1264 def test_revertDuringTest(self): 1265 """ 1266 C{patch()} return a L{monkey.MonkeyPatcher} object that can be used to 1267 restore the original values before the end of the test. 1268 """ 1269 patch = self.test.patch(self, "objectToPatch", self.patchedValue) 1270 patch.restore() 1271 self.assertEqual(self.objectToPatch, self.originalValue) 1272 1273 def test_revertAndRepatch(self): 1274 """ 1275 The returned L{monkey.MonkeyPatcher} object can re-apply the patch 1276 during the test run. 1277 """ 1278 patch = self.test.patch(self, "objectToPatch", self.patchedValue) 1279 patch.restore() 1280 patch.patch() 1281 self.assertEqual(self.objectToPatch, self.patchedValue) 1282 1283 def test_successivePatches(self): 1284 """ 1285 Successive patches are applied and reverted just like a single patch. 1286 """ 1287 self.test.patch(self, "objectToPatch", self.patchedValue) 1288 self.assertEqual(self.objectToPatch, self.patchedValue) 1289 self.test.patch(self, "objectToPatch", "second value") 1290 self.assertEqual(self.objectToPatch, "second value") 1291 self.test.run(reporter.Reporter()) 1292 self.assertEqual(self.objectToPatch, self.originalValue) 1293 1294 1295class SynchronousMonkeyPatchTests(MonkeyPatchMixin, unittest.SynchronousTestCase): 1296 """ 1297 Tests for the patch() helper method in the synchronous case. 1298 1299 See L{twisted.trial.test.test_tests.MonkeyPatchMixin} 1300 """ 1301 1302 TestCase = unittest.SynchronousTestCase 1303 1304 1305class AsynchronousMonkeyPatchTests(MonkeyPatchMixin, unittest.TestCase): 1306 """ 1307 Tests for the patch() helper method in the asynchronous case. 1308 1309 See L{twisted.trial.test.test_tests.MonkeyPatchMixin} 1310 """ 1311 1312 TestCase = unittest.TestCase 1313 1314 1315class IterateTestsMixin: 1316 """ 1317 L{_iterateTests} returns a list of all test cases in a test suite or test 1318 case. 1319 """ 1320 1321 def test_iterateTestCase(self): 1322 """ 1323 L{_iterateTests} on a single test case returns a list containing that 1324 test case. 1325 """ 1326 test = self.TestCase() 1327 self.assertEqual([test], list(_iterateTests(test))) 1328 1329 def test_iterateSingletonTestSuite(self): 1330 """ 1331 L{_iterateTests} on a test suite that contains a single test case 1332 returns a list containing that test case. 1333 """ 1334 test = self.TestCase() 1335 suite = runner.TestSuite([test]) 1336 self.assertEqual([test], list(_iterateTests(suite))) 1337 1338 def test_iterateNestedTestSuite(self): 1339 """ 1340 L{_iterateTests} returns tests that are in nested test suites. 1341 """ 1342 test = self.TestCase() 1343 suite = runner.TestSuite([runner.TestSuite([test])]) 1344 self.assertEqual([test], list(_iterateTests(suite))) 1345 1346 def test_iterateIsLeftToRightDepthFirst(self): 1347 """ 1348 L{_iterateTests} returns tests in left-to-right, depth-first order. 1349 """ 1350 test = self.TestCase() 1351 suite = runner.TestSuite([runner.TestSuite([test]), self]) 1352 self.assertEqual([test, self], list(_iterateTests(suite))) 1353 1354 1355class SynchronousIterateTestsTests(IterateTestsMixin, unittest.SynchronousTestCase): 1356 """ 1357 Check that L{_iterateTests} returns a list of all test cases in a test suite 1358 or test case for synchronous tests. 1359 1360 See L{twisted.trial.test.test_tests.IterateTestsMixin} 1361 """ 1362 1363 TestCase = unittest.SynchronousTestCase 1364 1365 1366class AsynchronousIterateTestsTests(IterateTestsMixin, unittest.TestCase): 1367 """ 1368 Check that L{_iterateTests} returns a list of all test cases in a test suite 1369 or test case for asynchronous tests. 1370 1371 See L{twisted.trial.test.test_tests.IterateTestsMixin} 1372 """ 1373 1374 TestCase = unittest.TestCase 1375 1376 1377class TrialGeneratorFunctionTests(unittest.SynchronousTestCase): 1378 """ 1379 Tests for generator function methods in test cases. 1380 """ 1381 1382 def test_errorOnGeneratorFunction(self): 1383 """ 1384 In a TestCase, a test method which is a generator function is reported 1385 as an error, as such a method will never run assertions. 1386 """ 1387 1388 class GeneratorTestCase(unittest.TestCase): 1389 """ 1390 A fake TestCase for testing purposes. 1391 """ 1392 1393 def test_generator(self): 1394 """ 1395 A method which is also a generator function, for testing 1396 purposes. 1397 """ 1398 self.fail("this should never be reached") 1399 yield 1400 1401 testCase = GeneratorTestCase("test_generator") 1402 result = reporter.TestResult() 1403 testCase.run(result) 1404 self.assertEqual(len(result.failures), 0) 1405 self.assertEqual(len(result.errors), 1) 1406 self.assertIn( 1407 "GeneratorTestCase.test_generator", result.errors[0][1].value.args[0] 1408 ) 1409 self.assertIn( 1410 "GeneratorTestCase testMethod=test_generator", 1411 result.errors[0][1].value.args[0], 1412 ) 1413 self.assertIn( 1414 "is a generator function and therefore will never run", 1415 result.errors[0][1].value.args[0], 1416 ) 1417 1418 def test_synchronousTestCaseErrorOnGeneratorFunction(self): 1419 """ 1420 In a SynchronousTestCase, a test method which is a generator function 1421 is reported as an error, as such a method will never run assertions. 1422 """ 1423 1424 class GeneratorSynchronousTestCase(unittest.SynchronousTestCase): 1425 """ 1426 A fake SynchronousTestCase for testing purposes. 1427 """ 1428 1429 def test_generator(self): 1430 """ 1431 A method which is also a generator function, for testing 1432 purposes. 1433 """ 1434 self.fail("this should never be reached") 1435 yield 1436 1437 testCase = GeneratorSynchronousTestCase("test_generator") 1438 result = reporter.TestResult() 1439 testCase.run(result) 1440 self.assertEqual(len(result.failures), 0) 1441 self.assertEqual(len(result.errors), 1) 1442 self.assertIn( 1443 "GeneratorSynchronousTestCase.test_generator", 1444 result.errors[0][1].value.args[0], 1445 ) 1446 self.assertIn( 1447 "GeneratorSynchronousTestCase testMethod=test_generator", 1448 result.errors[0][1].value.args[0], 1449 ) 1450 self.assertIn( 1451 "is a generator function and therefore will never run", 1452 result.errors[0][1].value.args[0], 1453 ) 1454