~bzr/ubuntu/natty/python-testtools/bzr-ppa

« back to all changes in this revision

Viewing changes to testtools/tests/test_testtools.py

  • Committer: Robert Collins
  • Date: 2010-11-14 15:49:58 UTC
  • mfrom: (16.11.4 upstream)
  • Revision ID: robertc@robertcollins.net-20101114154958-lwb16rdhehq6q020
New snapshot for testing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (c) 2008 Jonathan M. Lange. See LICENSE for details.
 
1
# Copyright (c) 2008-2010 Jonathan M. Lange. See LICENSE for details.
2
2
 
3
3
"""Tests for extensions to the base test library."""
4
4
 
 
5
from pprint import pformat
5
6
import sys
6
7
import unittest
7
8
 
8
9
from testtools import (
 
10
    ErrorHolder,
 
11
    MultipleExceptions,
 
12
    PlaceHolder,
9
13
    TestCase,
10
14
    clone_test_with_new_id,
11
15
    content,
16
20
    )
17
21
from testtools.matchers import (
18
22
    Equals,
 
23
    MatchesException,
 
24
    Raises,
19
25
    )
20
26
from testtools.tests.helpers import (
21
27
    an_exc_info,
26
32
    )
27
33
 
28
34
 
 
35
class TestPlaceHolder(TestCase):
 
36
 
 
37
    def makePlaceHolder(self, test_id="foo", short_description=None):
 
38
        return PlaceHolder(test_id, short_description)
 
39
 
 
40
    def test_id_comes_from_constructor(self):
 
41
        # The id() of a PlaceHolder is whatever you pass into the constructor.
 
42
        test = PlaceHolder("test id")
 
43
        self.assertEqual("test id", test.id())
 
44
 
 
45
    def test_shortDescription_is_id(self):
 
46
        # The shortDescription() of a PlaceHolder is the id, by default.
 
47
        test = PlaceHolder("test id")
 
48
        self.assertEqual(test.id(), test.shortDescription())
 
49
 
 
50
    def test_shortDescription_specified(self):
 
51
        # If a shortDescription is provided to the constructor, then
 
52
        # shortDescription() returns that instead.
 
53
        test = PlaceHolder("test id", "description")
 
54
        self.assertEqual("description", test.shortDescription())
 
55
 
 
56
    def test_repr_just_id(self):
 
57
        # repr(placeholder) shows you how the object was constructed.
 
58
        test = PlaceHolder("test id")
 
59
        self.assertEqual(
 
60
            "<testtools.testcase.PlaceHolder(%s)>" % repr(test.id()),
 
61
            repr(test))
 
62
 
 
63
    def test_repr_with_description(self):
 
64
        # repr(placeholder) shows you how the object was constructed.
 
65
        test = PlaceHolder("test id", "description")
 
66
        self.assertEqual(
 
67
            "<testtools.testcase.PlaceHolder(%r, %r)>" % (
 
68
                test.id(), test.shortDescription()),
 
69
            repr(test))
 
70
 
 
71
    def test_counts_as_one_test(self):
 
72
        # A placeholder test counts as one test.
 
73
        test = self.makePlaceHolder()
 
74
        self.assertEqual(1, test.countTestCases())
 
75
 
 
76
    def test_str_is_id(self):
 
77
        # str(placeholder) is always the id(). We are not barbarians.
 
78
        test = self.makePlaceHolder()
 
79
        self.assertEqual(test.id(), str(test))
 
80
 
 
81
    def test_runs_as_success(self):
 
82
        # When run, a PlaceHolder test records a success.
 
83
        test = self.makePlaceHolder()
 
84
        log = []
 
85
        test.run(LoggingResult(log))
 
86
        self.assertEqual(
 
87
            [('startTest', test), ('addSuccess', test), ('stopTest', test)],
 
88
            log)
 
89
 
 
90
    def test_call_is_run(self):
 
91
        # A PlaceHolder can be called, in which case it behaves like run.
 
92
        test = self.makePlaceHolder()
 
93
        run_log = []
 
94
        test.run(LoggingResult(run_log))
 
95
        call_log = []
 
96
        test(LoggingResult(call_log))
 
97
        self.assertEqual(run_log, call_log)
 
98
 
 
99
    def test_runs_without_result(self):
 
100
        # A PlaceHolder can be run without a result, in which case there's no
 
101
        # way to actually get at the result.
 
102
        self.makePlaceHolder().run()
 
103
 
 
104
    def test_debug(self):
 
105
        # A PlaceHolder can be debugged.
 
106
        self.makePlaceHolder().debug()
 
107
 
 
108
 
 
109
class TestErrorHolder(TestCase):
 
110
 
 
111
    def makeException(self):
 
112
        try:
 
113
            raise RuntimeError("danger danger")
 
114
        except:
 
115
            return sys.exc_info()
 
116
 
 
117
    def makePlaceHolder(self, test_id="foo", error=None,
 
118
                        short_description=None):
 
119
        if error is None:
 
120
            error = self.makeException()
 
121
        return ErrorHolder(test_id, error, short_description)
 
122
 
 
123
    def test_id_comes_from_constructor(self):
 
124
        # The id() of a PlaceHolder is whatever you pass into the constructor.
 
125
        test = ErrorHolder("test id", self.makeException())
 
126
        self.assertEqual("test id", test.id())
 
127
 
 
128
    def test_shortDescription_is_id(self):
 
129
        # The shortDescription() of a PlaceHolder is the id, by default.
 
130
        test = ErrorHolder("test id", self.makeException())
 
131
        self.assertEqual(test.id(), test.shortDescription())
 
132
 
 
133
    def test_shortDescription_specified(self):
 
134
        # If a shortDescription is provided to the constructor, then
 
135
        # shortDescription() returns that instead.
 
136
        test = ErrorHolder("test id", self.makeException(), "description")
 
137
        self.assertEqual("description", test.shortDescription())
 
138
 
 
139
    def test_repr_just_id(self):
 
140
        # repr(placeholder) shows you how the object was constructed.
 
141
        error = self.makeException()
 
142
        test = ErrorHolder("test id", error)
 
143
        self.assertEqual(
 
144
            "<testtools.testcase.ErrorHolder(%r, %r)>" % (test.id(), error),
 
145
            repr(test))
 
146
 
 
147
    def test_repr_with_description(self):
 
148
        # repr(placeholder) shows you how the object was constructed.
 
149
        error = self.makeException()
 
150
        test = ErrorHolder("test id", error, "description")
 
151
        self.assertEqual(
 
152
            "<testtools.testcase.ErrorHolder(%r, %r, %r)>" % (
 
153
                test.id(), error, test.shortDescription()),
 
154
            repr(test))
 
155
 
 
156
    def test_counts_as_one_test(self):
 
157
        # A placeholder test counts as one test.
 
158
        test = self.makePlaceHolder()
 
159
        self.assertEqual(1, test.countTestCases())
 
160
 
 
161
    def test_str_is_id(self):
 
162
        # str(placeholder) is always the id(). We are not barbarians.
 
163
        test = self.makePlaceHolder()
 
164
        self.assertEqual(test.id(), str(test))
 
165
 
 
166
    def test_runs_as_error(self):
 
167
        # When run, a PlaceHolder test records a success.
 
168
        error = self.makeException()
 
169
        test = self.makePlaceHolder(error=error)
 
170
        log = []
 
171
        test.run(LoggingResult(log))
 
172
        self.assertEqual(
 
173
            [('startTest', test),
 
174
             ('addError', test, error),
 
175
             ('stopTest', test)], log)
 
176
 
 
177
    def test_call_is_run(self):
 
178
        # A PlaceHolder can be called, in which case it behaves like run.
 
179
        test = self.makePlaceHolder()
 
180
        run_log = []
 
181
        test.run(LoggingResult(run_log))
 
182
        call_log = []
 
183
        test(LoggingResult(call_log))
 
184
        self.assertEqual(run_log, call_log)
 
185
 
 
186
    def test_runs_without_result(self):
 
187
        # A PlaceHolder can be run without a result, in which case there's no
 
188
        # way to actually get at the result.
 
189
        self.makePlaceHolder().run()
 
190
 
 
191
    def test_debug(self):
 
192
        # A PlaceHolder can be debugged.
 
193
        self.makePlaceHolder().debug()
 
194
 
 
195
 
29
196
class TestEquality(TestCase):
30
197
    """Test `TestCase`'s equality implementation."""
31
198
 
47
214
 
48
215
    def test_formatTypes_single(self):
49
216
        # Given a single class, _formatTypes returns the name.
50
 
        class Foo:
 
217
        class Foo(object):
51
218
            pass
52
219
        self.assertEqual('Foo', self._formatTypes(Foo))
53
220
 
54
221
    def test_formatTypes_multiple(self):
55
222
        # Given multiple types, _formatTypes returns the names joined by
56
223
        # commas.
57
 
        class Foo:
 
224
        class Foo(object):
58
225
            pass
59
 
        class Bar:
 
226
        class Bar(object):
60
227
            pass
61
228
        self.assertEqual('Foo, Bar', self._formatTypes([Foo, Bar]))
62
229
 
81
248
 
82
249
    def test_assertRaises_fails_when_different_error_raised(self):
83
250
        # assertRaises re-raises an exception that it didn't expect.
84
 
        self.assertRaises(
85
 
            ZeroDivisionError,
86
 
            self.assertRaises,
87
 
                RuntimeError, self.raiseError, ZeroDivisionError)
 
251
        self.assertThat(lambda: self.assertRaises(RuntimeError,
 
252
            self.raiseError, ZeroDivisionError),
 
253
            Raises(MatchesException(ZeroDivisionError)))
88
254
 
89
255
    def test_assertRaises_returns_the_raised_exception(self):
90
256
        # assertRaises returns the exception object that was raised. This is
164
330
    def test_assertIsInstance(self):
165
331
        # assertIsInstance asserts that an object is an instance of a class.
166
332
 
167
 
        class Foo:
 
333
        class Foo(object):
168
334
            """Simple class for testing assertIsInstance."""
169
335
 
170
336
        foo = Foo()
174
340
        # assertIsInstance asserts that an object is an instance of one of a
175
341
        # group of classes.
176
342
 
177
 
        class Foo:
 
343
        class Foo(object):
178
344
            """Simple class for testing assertIsInstance."""
179
345
 
180
 
        class Bar:
 
346
        class Bar(object):
181
347
            """Another simple class for testing assertIsInstance."""
182
348
 
183
349
        foo = Foo()
188
354
        # assertIsInstance(obj, klass) fails the test when obj is not an
189
355
        # instance of klass.
190
356
 
191
 
        class Foo:
 
357
        class Foo(object):
192
358
            """Simple class for testing assertIsInstance."""
193
359
 
194
360
        self.assertFails(
199
365
        # assertIsInstance(obj, (klass1, klass2)) fails the test when obj is
200
366
        # not an instance of klass1 or klass2.
201
367
 
202
 
        class Foo:
 
368
        class Foo(object):
203
369
            """Simple class for testing assertIsInstance."""
204
370
 
205
 
        class Bar:
 
371
        class Bar(object):
206
372
            """Another simple class for testing assertIsInstance."""
207
373
 
208
374
        self.assertFails(
251
417
            'None is None: foo bar', self.assertIsNot, None, None, "foo bar")
252
418
 
253
419
    def test_assertThat_matches_clean(self):
254
 
        class Matcher:
 
420
        class Matcher(object):
255
421
            def match(self, foo):
256
422
                return None
257
423
        self.assertThat("foo", Matcher())
258
424
 
259
425
    def test_assertThat_mismatch_raises_description(self):
260
426
        calls = []
261
 
        class Mismatch:
 
427
        class Mismatch(object):
262
428
            def __init__(self, thing):
263
429
                self.thing = thing
264
430
            def describe(self):
266
432
                return "object is not a thing"
267
433
            def get_details(self):
268
434
                return {}
269
 
        class Matcher:
 
435
        class Matcher(object):
270
436
            def match(self, thing):
271
437
                calls.append(('match', thing))
272
438
                return Mismatch(thing)
284
450
            ], calls)
285
451
        self.assertFalse(result.wasSuccessful())
286
452
 
 
453
    def test_assertEqual_nice_formatting(self):
 
454
        message = "These things ought not be equal."
 
455
        a = ['apple', 'banana', 'cherry']
 
456
        b = {'Thatcher': 'One who mends roofs of straw',
 
457
             'Major': 'A military officer, ranked below colonel',
 
458
             'Blair': 'To shout loudly',
 
459
             'Brown': 'The colour of healthy human faeces'}
 
460
        expected_error = '\n'.join(
 
461
            [message,
 
462
             'not equal:',
 
463
             'a = %s' % pformat(a),
 
464
             'b = %s' % pformat(b),
 
465
             ''])
 
466
        expected_error = '\n'.join([
 
467
            'Match failed. Matchee: "%r"' % b,
 
468
            'Matcher: Annotate(%r, Equals(%r))' % (message, a),
 
469
            'Difference: !=:',
 
470
            'reference = %s' % pformat(a),
 
471
            'actual = %s' % pformat(b),
 
472
            ': ' + message,
 
473
            ''
 
474
            ])
 
475
        self.assertFails(expected_error, self.assertEqual, a, b, message)
 
476
        self.assertFails(expected_error, self.assertEquals, a, b, message)
 
477
        self.assertFails(expected_error, self.failUnlessEqual, a, b, message)
 
478
 
 
479
    def test_assertEqual_formatting_no_message(self):
 
480
        a = "cat"
 
481
        b = "dog"
 
482
        expected_error = '\n'.join([
 
483
            'Match failed. Matchee: "dog"',
 
484
            'Matcher: Equals(\'cat\')',
 
485
            'Difference: \'cat\' != \'dog\'',
 
486
            ''
 
487
            ])
 
488
        self.assertFails(expected_error, self.assertEqual, a, b)
 
489
        self.assertFails(expected_error, self.assertEquals, a, b)
 
490
        self.assertFails(expected_error, self.failUnlessEqual, a, b)
 
491
 
287
492
 
288
493
class TestAddCleanup(TestCase):
289
494
    """Tests for TestCase.addCleanup."""
402
607
        def raiseKeyboardInterrupt():
403
608
            raise KeyboardInterrupt()
404
609
        self.test.addCleanup(raiseKeyboardInterrupt)
405
 
        self.assertRaises(
406
 
            KeyboardInterrupt, self.test.run, self.logging_result)
 
610
        self.assertThat(lambda:self.test.run(self.logging_result),
 
611
            Raises(MatchesException(KeyboardInterrupt)))
 
612
 
 
613
    def test_all_errors_from_MultipleExceptions_reported(self):
 
614
        # When a MultipleExceptions exception is caught, all the errors are
 
615
        # reported.
 
616
        def raiseMany():
 
617
            try:
 
618
                1/0
 
619
            except Exception:
 
620
                exc_info1 = sys.exc_info()
 
621
            try:
 
622
                1/0
 
623
            except Exception:
 
624
                exc_info2 = sys.exc_info()
 
625
            raise MultipleExceptions(exc_info1, exc_info2)
 
626
        self.test.addCleanup(raiseMany)
 
627
        self.logging_result = ExtendedTestResult()
 
628
        self.test.run(self.logging_result)
 
629
        self.assertEqual(['startTest', 'addError', 'stopTest'],
 
630
            [event[0] for event in self.logging_result._events])
 
631
        self.assertEqual(set(['traceback', 'traceback-1']),
 
632
            set(self.logging_result._events[1][2].keys()))
407
633
 
408
634
    def test_multipleCleanupErrorsReported(self):
409
635
        # Errors from all failing cleanups are reported as separate backtraces.
567
793
        self.assertEqual(oldName, test.id(),
568
794
            "the original test instance should be unchanged.")
569
795
 
 
796
    def test_cloned_testcase_does_not_share_details(self):
 
797
        """A cloned TestCase does not share the details dict."""
 
798
        class Test(TestCase):
 
799
            def test_foo(self):
 
800
                self.addDetail(
 
801
                    'foo', content.Content('text/plain', lambda: 'foo'))
 
802
        orig_test = Test('test_foo')
 
803
        cloned_test = clone_test_with_new_id(orig_test, self.getUniqueString())
 
804
        orig_test.run(unittest.TestResult())
 
805
        self.assertEqual('foo', orig_test.getDetails()['foo'].iter_bytes())
 
806
        self.assertEqual(None, cloned_test.getDetails().get('foo'))
 
807
 
570
808
 
571
809
class TestDetailsProvided(TestWithDetails):
572
810
 
617
855
 
618
856
    def test_addDetails_from_Mismatch(self):
619
857
        content = self.get_content()
620
 
        class Mismatch:
 
858
        class Mismatch(object):
621
859
            def describe(self):
622
860
                return "Mismatch"
623
861
            def get_details(self):
624
862
                return {"foo": content}
625
 
        class Matcher:
 
863
        class Matcher(object):
626
864
            def match(self, thing):
627
865
                return Mismatch()
628
866
            def __str__(self):
635
873
 
636
874
    def test_multiple_addDetails_from_Mismatch(self):
637
875
        content = self.get_content()
638
 
        class Mismatch:
 
876
        class Mismatch(object):
639
877
            def describe(self):
640
878
                return "Mismatch"
641
879
            def get_details(self):
642
880
                return {"foo": content, "bar": content}
643
 
        class Matcher:
 
881
        class Matcher(object):
644
882
            def match(self, thing):
645
883
                return Mismatch()
646
884
            def __str__(self):
653
891
 
654
892
    def test_addDetails_with_same_name_as_key_from_get_details(self):
655
893
        content = self.get_content()
656
 
        class Mismatch:
 
894
        class Mismatch(object):
657
895
            def describe(self):
658
896
                return "Mismatch"
659
897
            def get_details(self):
660
898
                return {"foo": content}
661
 
        class Matcher:
 
899
        class Matcher(object):
662
900
            def match(self, thing):
663
901
                return Mismatch()
664
902
            def __str__(self):
698
936
    """Tests for skipping of tests functionality."""
699
937
 
700
938
    def test_skip_causes_skipException(self):
701
 
        self.assertRaises(self.skipException, self.skip, "Skip this test")
 
939
        self.assertThat(lambda:self.skip("Skip this test"),
 
940
            Raises(MatchesException(self.skipException)))
702
941
 
703
942
    def test_can_use_skipTest(self):
704
 
        self.assertRaises(self.skipException, self.skipTest, "Skip this test")
 
943
        self.assertThat(lambda:self.skipTest("Skip this test"),
 
944
            Raises(MatchesException(self.skipException)))
705
945
 
706
946
    def test_skip_without_reason_works(self):
707
947
        class Test(TestCase):
727
967
        test.run(result)
728
968
        case = result._events[0][1]
729
969
        self.assertEqual([('startTest', case),
730
 
            ('addSkip', case, "Text attachment: reason\n------------\n"
731
 
             "skipping this test\n------------\n"), ('stopTest', case)],
 
970
            ('addSkip', case, "skipping this test"), ('stopTest', case)],
732
971
            calls)
733
972
 
734
973
    def test_skipException_in_test_method_calls_result_addSkip(self):
740
979
        test.run(result)
741
980
        case = result._events[0][1]
742
981
        self.assertEqual([('startTest', case),
743
 
            ('addSkip', case, "Text attachment: reason\n------------\n"
744
 
             "skipping this test\n------------\n"), ('stopTest', case)],
 
982
            ('addSkip', case, "skipping this test"), ('stopTest', case)],
745
983
            result._events)
746
984
 
747
985
    def test_skip__in_setup_with_old_result_object_calls_addSuccess(self):
823
1061
        class Case(TestCase):
824
1062
            def method(self):
825
1063
                self.addOnException(events.index)
826
 
                self.assertRaises(ValueError, self.onException, an_exc_info)
 
1064
                self.assertThat(lambda: self.onException(an_exc_info),
 
1065
                    Raises(MatchesException(ValueError)))
827
1066
        case = Case("method")
828
1067
        case.run()
829
1068
        self.assertThat(events, Equals([]))
830
1069
 
831
1070
 
 
1071
class TestPatchSupport(TestCase):
 
1072
 
 
1073
    class Case(TestCase):
 
1074
        def test(self):
 
1075
            pass
 
1076
 
 
1077
    def test_patch(self):
 
1078
        # TestCase.patch masks obj.attribute with the new value.
 
1079
        self.foo = 'original'
 
1080
        test = self.Case('test')
 
1081
        test.patch(self, 'foo', 'patched')
 
1082
        self.assertEqual('patched', self.foo)
 
1083
 
 
1084
    def test_patch_restored_after_run(self):
 
1085
        # TestCase.patch masks obj.attribute with the new value, but restores
 
1086
        # the original value after the test is finished.
 
1087
        self.foo = 'original'
 
1088
        test = self.Case('test')
 
1089
        test.patch(self, 'foo', 'patched')
 
1090
        test.run()
 
1091
        self.assertEqual('original', self.foo)
 
1092
 
 
1093
    def test_successive_patches_apply(self):
 
1094
        # TestCase.patch can be called multiple times per test. Each time you
 
1095
        # call it, it overrides the original value.
 
1096
        self.foo = 'original'
 
1097
        test = self.Case('test')
 
1098
        test.patch(self, 'foo', 'patched')
 
1099
        test.patch(self, 'foo', 'second')
 
1100
        self.assertEqual('second', self.foo)
 
1101
 
 
1102
    def test_successive_patches_restored_after_run(self):
 
1103
        # TestCase.patch restores the original value, no matter how many times
 
1104
        # it was called.
 
1105
        self.foo = 'original'
 
1106
        test = self.Case('test')
 
1107
        test.patch(self, 'foo', 'patched')
 
1108
        test.patch(self, 'foo', 'second')
 
1109
        test.run()
 
1110
        self.assertEqual('original', self.foo)
 
1111
 
 
1112
    def test_patch_nonexistent_attribute(self):
 
1113
        # TestCase.patch can be used to patch a non-existent attribute.
 
1114
        test = self.Case('test')
 
1115
        test.patch(self, 'doesntexist', 'patched')
 
1116
        self.assertEqual('patched', self.doesntexist)
 
1117
 
 
1118
    def test_restore_nonexistent_attribute(self):
 
1119
        # TestCase.patch can be used to patch a non-existent attribute, after
 
1120
        # the test run, the attribute is then removed from the object.
 
1121
        test = self.Case('test')
 
1122
        test.patch(self, 'doesntexist', 'patched')
 
1123
        test.run()
 
1124
        marker = object()
 
1125
        value = getattr(self, 'doesntexist', marker)
 
1126
        self.assertIs(marker, value)
 
1127
 
 
1128
 
832
1129
def test_suite():
833
1130
    from unittest import TestLoader
834
1131
    return TestLoader().loadTestsFromName(__name__)