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

« back to all changes in this revision

Viewing changes to testtools/tests/test_monkey.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) 2010 Twisted Matrix Laboratories.
 
2
# See LICENSE for details.
 
3
 
 
4
"""Tests for testtools.monkey."""
 
5
 
 
6
from testtools import TestCase
 
7
from testtools.matchers import MatchesException, Raises
 
8
from testtools.monkey import MonkeyPatcher, patch
 
9
 
 
10
 
 
11
class TestObj:
 
12
 
 
13
    def __init__(self):
 
14
        self.foo = 'foo value'
 
15
        self.bar = 'bar value'
 
16
        self.baz = 'baz value'
 
17
 
 
18
 
 
19
class MonkeyPatcherTest(TestCase):
 
20
    """
 
21
    Tests for 'MonkeyPatcher' monkey-patching class.
 
22
    """
 
23
 
 
24
    def setUp(self):
 
25
        super(MonkeyPatcherTest, self).setUp()
 
26
        self.test_object = TestObj()
 
27
        self.original_object = TestObj()
 
28
        self.monkey_patcher = MonkeyPatcher()
 
29
 
 
30
    def test_empty(self):
 
31
        # A monkey patcher without patches doesn't change a thing.
 
32
        self.monkey_patcher.patch()
 
33
 
 
34
        # We can't assert that all state is unchanged, but at least we can
 
35
        # check our test object.
 
36
        self.assertEquals(self.original_object.foo, self.test_object.foo)
 
37
        self.assertEquals(self.original_object.bar, self.test_object.bar)
 
38
        self.assertEquals(self.original_object.baz, self.test_object.baz)
 
39
 
 
40
    def test_construct_with_patches(self):
 
41
        # Constructing a 'MonkeyPatcher' with patches adds all of the given
 
42
        # patches to the patch list.
 
43
        patcher = MonkeyPatcher((self.test_object, 'foo', 'haha'),
 
44
                                (self.test_object, 'bar', 'hehe'))
 
45
        patcher.patch()
 
46
        self.assertEquals('haha', self.test_object.foo)
 
47
        self.assertEquals('hehe', self.test_object.bar)
 
48
        self.assertEquals(self.original_object.baz, self.test_object.baz)
 
49
 
 
50
    def test_patch_existing(self):
 
51
        # Patching an attribute that exists sets it to the value defined in the
 
52
        # patch.
 
53
        self.monkey_patcher.add_patch(self.test_object, 'foo', 'haha')
 
54
        self.monkey_patcher.patch()
 
55
        self.assertEquals(self.test_object.foo, 'haha')
 
56
 
 
57
    def test_patch_non_existing(self):
 
58
        # Patching a non-existing attribute sets it to the value defined in
 
59
        # the patch.
 
60
        self.monkey_patcher.add_patch(self.test_object, 'doesntexist', 'value')
 
61
        self.monkey_patcher.patch()
 
62
        self.assertEquals(self.test_object.doesntexist, 'value')
 
63
 
 
64
    def test_restore_non_existing(self):
 
65
        # Restoring a value that didn't exist before the patch deletes the
 
66
        # value.
 
67
        self.monkey_patcher.add_patch(self.test_object, 'doesntexist', 'value')
 
68
        self.monkey_patcher.patch()
 
69
        self.monkey_patcher.restore()
 
70
        marker = object()
 
71
        self.assertIs(marker, getattr(self.test_object, 'doesntexist', marker))
 
72
 
 
73
    def test_patch_already_patched(self):
 
74
        # Adding a patch for an object and attribute that already have a patch
 
75
        # overrides the existing patch.
 
76
        self.monkey_patcher.add_patch(self.test_object, 'foo', 'blah')
 
77
        self.monkey_patcher.add_patch(self.test_object, 'foo', 'BLAH')
 
78
        self.monkey_patcher.patch()
 
79
        self.assertEquals(self.test_object.foo, 'BLAH')
 
80
        self.monkey_patcher.restore()
 
81
        self.assertEquals(self.test_object.foo, self.original_object.foo)
 
82
 
 
83
    def test_restore_twice_is_a_no_op(self):
 
84
        # Restoring an already-restored monkey patch is a no-op.
 
85
        self.monkey_patcher.add_patch(self.test_object, 'foo', 'blah')
 
86
        self.monkey_patcher.patch()
 
87
        self.monkey_patcher.restore()
 
88
        self.assertEquals(self.test_object.foo, self.original_object.foo)
 
89
        self.monkey_patcher.restore()
 
90
        self.assertEquals(self.test_object.foo, self.original_object.foo)
 
91
 
 
92
    def test_run_with_patches_decoration(self):
 
93
        # run_with_patches runs the given callable, passing in all arguments
 
94
        # and keyword arguments, and returns the return value of the callable.
 
95
        log = []
 
96
 
 
97
        def f(a, b, c=None):
 
98
            log.append((a, b, c))
 
99
            return 'foo'
 
100
 
 
101
        result = self.monkey_patcher.run_with_patches(f, 1, 2, c=10)
 
102
        self.assertEquals('foo', result)
 
103
        self.assertEquals([(1, 2, 10)], log)
 
104
 
 
105
    def test_repeated_run_with_patches(self):
 
106
        # We can call the same function with run_with_patches more than
 
107
        # once. All patches apply for each call.
 
108
        def f():
 
109
            return (self.test_object.foo, self.test_object.bar,
 
110
                    self.test_object.baz)
 
111
 
 
112
        self.monkey_patcher.add_patch(self.test_object, 'foo', 'haha')
 
113
        result = self.monkey_patcher.run_with_patches(f)
 
114
        self.assertEquals(
 
115
            ('haha', self.original_object.bar, self.original_object.baz),
 
116
            result)
 
117
        result = self.monkey_patcher.run_with_patches(f)
 
118
        self.assertEquals(
 
119
            ('haha', self.original_object.bar, self.original_object.baz),
 
120
            result)
 
121
 
 
122
    def test_run_with_patches_restores(self):
 
123
        # run_with_patches restores the original values after the function has
 
124
        # executed.
 
125
        self.monkey_patcher.add_patch(self.test_object, 'foo', 'haha')
 
126
        self.assertEquals(self.original_object.foo, self.test_object.foo)
 
127
        self.monkey_patcher.run_with_patches(lambda: None)
 
128
        self.assertEquals(self.original_object.foo, self.test_object.foo)
 
129
 
 
130
    def test_run_with_patches_restores_on_exception(self):
 
131
        # run_with_patches restores the original values even when the function
 
132
        # raises an exception.
 
133
        def _():
 
134
            self.assertEquals(self.test_object.foo, 'haha')
 
135
            self.assertEquals(self.test_object.bar, 'blahblah')
 
136
            raise RuntimeError("Something went wrong!")
 
137
 
 
138
        self.monkey_patcher.add_patch(self.test_object, 'foo', 'haha')
 
139
        self.monkey_patcher.add_patch(self.test_object, 'bar', 'blahblah')
 
140
 
 
141
        self.assertThat(lambda:self.monkey_patcher.run_with_patches(_),
 
142
            Raises(MatchesException(RuntimeError("Something went wrong!"))))
 
143
        self.assertEquals(self.test_object.foo, self.original_object.foo)
 
144
        self.assertEquals(self.test_object.bar, self.original_object.bar)
 
145
 
 
146
 
 
147
class TestPatchHelper(TestCase):
 
148
 
 
149
    def test_patch_patches(self):
 
150
        # patch(obj, name, value) sets obj.name to value.
 
151
        test_object = TestObj()
 
152
        patch(test_object, 'foo', 42)
 
153
        self.assertEqual(42, test_object.foo)
 
154
 
 
155
    def test_patch_returns_cleanup(self):
 
156
        # patch(obj, name, value) returns a nullary callable that restores obj
 
157
        # to its original state when run.
 
158
        test_object = TestObj()
 
159
        original = test_object.foo
 
160
        cleanup = patch(test_object, 'foo', 42)
 
161
        cleanup()
 
162
        self.assertEqual(original, test_object.foo)
 
163
 
 
164
 
 
165
def test_suite():
 
166
    from unittest import TestLoader
 
167
    return TestLoader().loadTestsFromName(__name__)