1
# Copyright (c) 2010 Twisted Matrix Laboratories.
2
# See LICENSE for details.
4
"""Tests for testtools.monkey."""
6
from testtools import TestCase
7
from testtools.matchers import MatchesException, Raises
8
from testtools.monkey import MonkeyPatcher, patch
14
self.foo = 'foo value'
15
self.bar = 'bar value'
16
self.baz = 'baz value'
19
class MonkeyPatcherTest(TestCase):
21
Tests for 'MonkeyPatcher' monkey-patching class.
25
super(MonkeyPatcherTest, self).setUp()
26
self.test_object = TestObj()
27
self.original_object = TestObj()
28
self.monkey_patcher = MonkeyPatcher()
31
# A monkey patcher without patches doesn't change a thing.
32
self.monkey_patcher.patch()
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)
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'))
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)
50
def test_patch_existing(self):
51
# Patching an attribute that exists sets it to the value defined in the
53
self.monkey_patcher.add_patch(self.test_object, 'foo', 'haha')
54
self.monkey_patcher.patch()
55
self.assertEquals(self.test_object.foo, 'haha')
57
def test_patch_non_existing(self):
58
# Patching a non-existing attribute sets it to the value defined in
60
self.monkey_patcher.add_patch(self.test_object, 'doesntexist', 'value')
61
self.monkey_patcher.patch()
62
self.assertEquals(self.test_object.doesntexist, 'value')
64
def test_restore_non_existing(self):
65
# Restoring a value that didn't exist before the patch deletes the
67
self.monkey_patcher.add_patch(self.test_object, 'doesntexist', 'value')
68
self.monkey_patcher.patch()
69
self.monkey_patcher.restore()
71
self.assertIs(marker, getattr(self.test_object, 'doesntexist', marker))
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)
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)
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.
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)
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.
109
return (self.test_object.foo, self.test_object.bar,
110
self.test_object.baz)
112
self.monkey_patcher.add_patch(self.test_object, 'foo', 'haha')
113
result = self.monkey_patcher.run_with_patches(f)
115
('haha', self.original_object.bar, self.original_object.baz),
117
result = self.monkey_patcher.run_with_patches(f)
119
('haha', self.original_object.bar, self.original_object.baz),
122
def test_run_with_patches_restores(self):
123
# run_with_patches restores the original values after the function has
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)
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.
134
self.assertEquals(self.test_object.foo, 'haha')
135
self.assertEquals(self.test_object.bar, 'blahblah')
136
raise RuntimeError("Something went wrong!")
138
self.monkey_patcher.add_patch(self.test_object, 'foo', 'haha')
139
self.monkey_patcher.add_patch(self.test_object, 'bar', 'blahblah')
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)
147
class TestPatchHelper(TestCase):
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)
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)
162
self.assertEqual(original, test_object.foo)
166
from unittest import TestLoader
167
return TestLoader().loadTestsFromName(__name__)