Michael Foord | 1e68bec | 2012-03-03 22:24:30 +0000 | [diff] [blame] | 1 | # Copyright (C) 2007-2012 Michael Foord & the mock team |
| 2 | # E-mail: fuzzyman AT voidspace DOT org DOT uk |
| 3 | # http://www.voidspace.org.uk/python/mock/ |
| 4 | |
| 5 | import inspect |
| 6 | |
| 7 | from tests.support import unittest2 |
| 8 | |
| 9 | from mock import Mock, mocksignature, patch |
| 10 | |
| 11 | |
| 12 | class Something(object): |
| 13 | def __init__(self, foo, bar=10): |
| 14 | pass |
| 15 | def __call__(self, foo, bar=5): |
| 16 | pass |
| 17 | |
| 18 | something = Something(1, 2) |
| 19 | |
| 20 | |
| 21 | def f(a, b, c): |
| 22 | pass |
| 23 | |
| 24 | |
| 25 | class TestMockSignature(unittest2.TestCase): |
| 26 | |
| 27 | def test_function(self): |
| 28 | def f(a): |
| 29 | pass |
| 30 | mock = Mock() |
| 31 | |
| 32 | f2 = mocksignature(f, mock) |
| 33 | self.assertIs(f2.mock, mock) |
| 34 | |
| 35 | self.assertRaises(TypeError, f2) |
| 36 | mock.return_value = 3 |
| 37 | self.assertEqual(f2('foo'), 3) |
| 38 | mock.assert_called_with('foo') |
| 39 | f2.mock.assert_called_with('foo') |
| 40 | |
| 41 | |
| 42 | def test_function_without_explicit_mock(self): |
| 43 | def f(a): |
| 44 | pass |
| 45 | |
| 46 | f2 = mocksignature(f) |
| 47 | self.assertIsInstance(f2.mock, Mock) |
| 48 | |
| 49 | self.assertRaises(TypeError, f2) |
| 50 | f2.mock.return_value = 3 |
| 51 | self.assertEqual(f2('foo'), 3) |
| 52 | f2.mock.assert_called_with('foo') |
| 53 | |
| 54 | |
| 55 | def test_method(self): |
| 56 | class Foo(object): |
| 57 | def method(self, a, b): |
| 58 | pass |
| 59 | |
| 60 | f = Foo() |
| 61 | mock = Mock() |
| 62 | mock.return_value = 3 |
| 63 | f.method = mocksignature(f.method, mock) |
| 64 | self.assertEqual(f.method('foo', 'bar'), 3) |
| 65 | mock.assert_called_with('foo', 'bar') |
| 66 | |
| 67 | |
| 68 | def test_function_with_defaults(self): |
| 69 | def f(a, b=None): |
| 70 | pass |
| 71 | mock = Mock() |
| 72 | f2 = mocksignature(f, mock) |
| 73 | f2(3) |
| 74 | mock.assert_called_with(3, None) |
| 75 | mock.reset_mock() |
| 76 | |
| 77 | f2(1, 7) |
| 78 | mock.assert_called_with(1, 7) |
| 79 | mock.reset_mock() |
| 80 | |
| 81 | f2(b=1, a=7) |
| 82 | mock.assert_called_with(7, 1) |
| 83 | mock.reset_mock() |
| 84 | |
| 85 | a = object() |
| 86 | def f(a=a): |
| 87 | pass |
| 88 | f2 = mocksignature(f, mock) |
| 89 | f2() |
| 90 | mock.assert_called_with(a) |
| 91 | |
| 92 | |
| 93 | def test_introspection(self): |
| 94 | def f(a, *args, **kwargs): |
| 95 | pass |
| 96 | f2 = mocksignature(f, f) |
| 97 | self.assertEqual(inspect.getargspec(f), inspect.getargspec(f2)) |
| 98 | |
| 99 | def f(a, b=None, c=3, d=object()): |
| 100 | pass |
| 101 | f2 = mocksignature(f, f) |
| 102 | self.assertEqual(inspect.getargspec(f), inspect.getargspec(f2)) |
| 103 | |
| 104 | |
| 105 | def test_function_with_varargs_and_kwargs(self): |
| 106 | def f(a, b=None, *args, **kwargs): |
| 107 | return (a, b, args, kwargs) |
| 108 | f2 = mocksignature(f, f) |
| 109 | self.assertEqual(f2(3, 4, 5, x=6, y=9), (3, 4, (5,), {'x': 6, 'y': 9})) |
| 110 | self.assertEqual(f2(3, x=6, y=9, b='a'), (3, 'a', (), {'x': 6, 'y': 9})) |
| 111 | |
| 112 | def f(*args): |
| 113 | pass |
| 114 | g = mocksignature(f) |
| 115 | g.mock.return_value = 3 |
| 116 | self.assertEqual(g(1, 2, 'many'), 3) |
| 117 | self.assertEqual(g(), 3) |
| 118 | self.assertRaises(TypeError, lambda: g(a=None)) |
| 119 | |
| 120 | def f(**kwargs): |
| 121 | pass |
| 122 | g = mocksignature(f) |
| 123 | g.mock.return_value = 3 |
| 124 | self.assertEqual(g(), 3) |
| 125 | self.assertEqual(g(a=None, b=None), 3) |
| 126 | self.assertRaises(TypeError, lambda: g(None)) |
| 127 | |
| 128 | |
| 129 | def test_mocksignature_with_patch(self): |
| 130 | mock = Mock() |
| 131 | |
| 132 | def f(a, b, c): |
| 133 | pass |
| 134 | mock.f = f |
| 135 | |
| 136 | @patch.object(mock, 'f', mocksignature=True) |
| 137 | def test(mock_f): |
| 138 | self.assertRaises(TypeError, mock.f, 3, 4) |
| 139 | self.assertRaises(TypeError, mock.f, 3, 4, 5, 6) |
| 140 | mock.f(1, 2, 3) |
| 141 | |
| 142 | mock_f.assert_called_with(1, 2, 3) |
| 143 | mock.f.mock.assert_called_with(1, 2, 3) |
| 144 | |
| 145 | test() |
| 146 | |
| 147 | @patch('tests.support.SomeClass.wibble', mocksignature=True) |
| 148 | def test(mock_wibble): |
| 149 | from tests.support import SomeClass |
| 150 | |
| 151 | instance = SomeClass() |
| 152 | self.assertRaises(TypeError, instance.wibble, 1) |
| 153 | instance.wibble() |
| 154 | |
| 155 | mock_wibble.assert_called_with(instance) |
| 156 | instance.wibble.mock.assert_called_with(instance) |
| 157 | |
| 158 | test() |
| 159 | |
| 160 | |
| 161 | @unittest2.skipUnless(__debug__, 'assert disabled when run with -O/OO') |
| 162 | def test_mocksignature_with_reserved_arg(self): |
| 163 | def f(_mock_): |
| 164 | pass |
| 165 | self.assertRaises(AssertionError, lambda: mocksignature(f)) |
| 166 | |
| 167 | def f(_mock_=None): |
| 168 | pass |
| 169 | self.assertRaises(AssertionError, lambda: mocksignature(f)) |
| 170 | |
| 171 | def f(*_mock_): |
| 172 | pass |
| 173 | self.assertRaises(AssertionError, lambda: mocksignature(f)) |
| 174 | |
| 175 | def f(**_mock_): |
| 176 | pass |
| 177 | self.assertRaises(AssertionError, lambda: mocksignature(f)) |
| 178 | |
| 179 | |
| 180 | def test_mocksignature_class(self): |
| 181 | MockedSomething = mocksignature(Something) |
| 182 | |
| 183 | result = MockedSomething(5, 23) |
| 184 | self.assertIs(result, MockedSomething.mock.return_value) |
| 185 | |
| 186 | MockedSomething(1) |
| 187 | MockedSomething.mock.assert_caled_with(1, 10) |
| 188 | |
| 189 | self.assertRaises(TypeError, MockedSomething) |
| 190 | |
| 191 | |
| 192 | def test_mocksignature_callable(self): |
| 193 | mocked_something = mocksignature(something) |
| 194 | |
| 195 | result = mocked_something(5, 23) |
| 196 | self.assertIs(result, mocked_something.mock.return_value) |
| 197 | |
| 198 | mocked_something(1) |
| 199 | mocked_something.mock.assert_caled_with(1, 5) |
| 200 | |
| 201 | self.assertRaises(TypeError, mocked_something) |
| 202 | |
| 203 | |
| 204 | def test_patch_mocksignature_class(self): |
| 205 | original_something = Something |
| 206 | something_name = '%s.Something' % __name__ |
| 207 | @patch(something_name, mocksignature=True) |
| 208 | def test(MockSomething): |
| 209 | Something(3, 5) |
| 210 | MockSomething.assert_called_with(3, 5) |
| 211 | |
| 212 | Something(6) |
| 213 | MockSomething.assert_called_with(6, 10) |
| 214 | |
| 215 | self.assertRaises(TypeError, Something) |
| 216 | test() |
| 217 | self.assertIs(Something, original_something) |
| 218 | |
| 219 | |
| 220 | def test_patch_mocksignature_callable(self): |
| 221 | original_something = something |
| 222 | something_name = '%s.something' % __name__ |
| 223 | @patch(something_name, mocksignature=True) |
| 224 | def test(MockSomething): |
| 225 | something(3, 4) |
| 226 | MockSomething.assert_called_with(3, 4) |
| 227 | |
| 228 | something(6) |
| 229 | MockSomething.assert_called_with(6, 5) |
| 230 | |
| 231 | self.assertRaises(TypeError, something) |
| 232 | test() |
| 233 | self.assertIs(something, original_something) |
| 234 | |
| 235 | |
| 236 | def test_patchobject_mocksignature(self): |
| 237 | class something(object): |
| 238 | def meth(self, a, b, c): |
| 239 | pass |
| 240 | |
| 241 | original = something.__dict__['meth'] |
| 242 | |
| 243 | @patch.object(something, 'meth', mocksignature=True) |
| 244 | def test(_): |
| 245 | self.assertIsNot(something.__dict__['meth'], original) |
| 246 | thing = something() |
| 247 | thing.meth(1, 2, 3) |
| 248 | self.assertRaises(TypeError, thing.meth, 1) |
| 249 | |
| 250 | test() |
| 251 | self.assertIs(something.__dict__['meth'], original) |
| 252 | |
| 253 | thing = something() |
| 254 | |
| 255 | original = thing.meth |
| 256 | @patch.object(thing, 'meth', mocksignature=True) |
| 257 | def test(_): |
| 258 | thing.meth(1, 2, 3) |
| 259 | self.assertRaises(TypeError, thing.meth, 1) |
| 260 | |
| 261 | test() |
| 262 | self.assertEqual(thing.meth, original) |
| 263 | |
| 264 | # when patching instance methods using mocksignatures we used to |
| 265 | # replace the bound method with an instance attribute on unpatching. |
| 266 | self.assertNotIn('meth', thing.__dict__) |
| 267 | |
| 268 | |
| 269 | def test_assert_called_with(self): |
| 270 | func = mocksignature(f) |
| 271 | |
| 272 | self.assertRaises(AssertionError, func.assert_called_with) |
| 273 | self.assertRaises(AssertionError, func.assert_called_once_with) |
| 274 | |
| 275 | func(1, 2, 3) |
| 276 | func.assert_called_with(1, 2, 3) |
| 277 | self.assertRaises(AssertionError, func.assert_called_with, 4, 5, 6) |
| 278 | func.assert_called_once_with(1, 2, 3) |
| 279 | self.assertRaises(AssertionError, func.assert_called_once_with, |
| 280 | 4, 5, 6) |
| 281 | |
| 282 | |
| 283 | def test_mock_attributes(self): |
| 284 | func = mocksignature(f) |
| 285 | |
| 286 | return_value = func.return_value |
| 287 | self.assertIsInstance(return_value, Mock) |
| 288 | self.assertIsNone(func.side_effect) |
| 289 | self.assertFalse(func.called) |
| 290 | self.assertIsNone(func.call_args) |
| 291 | self.assertEqual(func.call_count, 0) |
| 292 | self.assertEqual(func.method_calls, []) |
| 293 | self.assertEqual(func.call_args_list, []) |
| 294 | self.assertIs(func._mock_children, func.mock._mock_children) |
| 295 | |
| 296 | self.assertIs(func(1, 2, 3), return_value) |
| 297 | |
| 298 | self.assertTrue(func.called) |
| 299 | self.assertEqual(func.call_args, ((1, 2, 3), {})) |
| 300 | self.assertEqual(func.call_count, 1) |
| 301 | self.assertEqual(func.method_calls, []) |
| 302 | self.assertEqual(func.call_args_list, [((1, 2, 3), {})]) |
| 303 | func.method_calls.append('foo') |
| 304 | |
| 305 | return_value() |
| 306 | func.reset_mock() |
| 307 | |
| 308 | self.assertEqual(return_value.call_count, False) |
| 309 | self.assertFalse(func.called) |
| 310 | self.assertIsNone(func.call_args) |
| 311 | self.assertEqual(func.call_count, 0) |
| 312 | self.assertEqual(func.method_calls, []) |
| 313 | self.assertEqual(func.call_args_list, []) |
| 314 | self.assertIs(func._mock_children, func.mock._mock_children) |
| 315 | |
| 316 | func.side_effect = KeyError |
| 317 | self.assertRaises(KeyError, func, 1, 2, 3) |
| 318 | self.assertTrue(func.called) |
| 319 | |
| 320 | func.side_effect = None |
| 321 | func.return_value = 'foo' |
| 322 | self.assertEqual(func(1, 2, 3), 'foo') |
| 323 | self.assertEqual(func.call_count, 2) |
| 324 | |
| 325 | |
| 326 | def test_return_value_from_existing_mock(self): |
| 327 | mock = Mock(return_value='foo') |
| 328 | func = mocksignature(f, mock) |
| 329 | self.assertEqual(func(1, 2, 3), 'foo') |
| 330 | |
| 331 | mock.return_value = 'bar' |
| 332 | self.assertEqual(func(1, 2, 3), 'bar') |
| 333 | |
| 334 | |
| 335 | def test_side_effect_from_existing_mock(self): |
| 336 | mock = Mock(side_effect=KeyError) |
| 337 | func = mocksignature(f, mock) |
| 338 | self.assertRaises(KeyError, func, 1, 2, 3) |
| 339 | |
| 340 | mock.side_effect = NameError |
| 341 | self.assertRaises(NameError, func, 1, 2, 3) |
| 342 | |
| 343 | |
| 344 | if __name__ == '__main__': |
| 345 | unittest2.main() |