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