1import asyncio 2import math 3import unittest 4import os 5import sys 6from unittest.mock import AsyncMock, Mock, MagicMock, _magics 7 8 9 10class TestMockingMagicMethods(unittest.TestCase): 11 12 def test_deleting_magic_methods(self): 13 mock = Mock() 14 self.assertFalse(hasattr(mock, '__getitem__')) 15 16 mock.__getitem__ = Mock() 17 self.assertTrue(hasattr(mock, '__getitem__')) 18 19 del mock.__getitem__ 20 self.assertFalse(hasattr(mock, '__getitem__')) 21 22 23 def test_magicmock_del(self): 24 mock = MagicMock() 25 # before using getitem 26 del mock.__getitem__ 27 self.assertRaises(TypeError, lambda: mock['foo']) 28 29 mock = MagicMock() 30 # this time use it first 31 mock['foo'] 32 del mock.__getitem__ 33 self.assertRaises(TypeError, lambda: mock['foo']) 34 35 36 def test_magic_method_wrapping(self): 37 mock = Mock() 38 def f(self, name): 39 return self, 'fish' 40 41 mock.__getitem__ = f 42 self.assertIsNot(mock.__getitem__, f) 43 self.assertEqual(mock['foo'], (mock, 'fish')) 44 self.assertEqual(mock.__getitem__('foo'), (mock, 'fish')) 45 46 mock.__getitem__ = mock 47 self.assertIs(mock.__getitem__, mock) 48 49 50 def test_magic_methods_isolated_between_mocks(self): 51 mock1 = Mock() 52 mock2 = Mock() 53 54 mock1.__iter__ = Mock(return_value=iter([])) 55 self.assertEqual(list(mock1), []) 56 self.assertRaises(TypeError, lambda: list(mock2)) 57 58 59 def test_repr(self): 60 mock = Mock() 61 self.assertEqual(repr(mock), "<Mock id='%s'>" % id(mock)) 62 mock.__repr__ = lambda s: 'foo' 63 self.assertEqual(repr(mock), 'foo') 64 65 66 def test_str(self): 67 mock = Mock() 68 self.assertEqual(str(mock), object.__str__(mock)) 69 mock.__str__ = lambda s: 'foo' 70 self.assertEqual(str(mock), 'foo') 71 72 73 def test_dict_methods(self): 74 mock = Mock() 75 76 self.assertRaises(TypeError, lambda: mock['foo']) 77 def _del(): 78 del mock['foo'] 79 def _set(): 80 mock['foo'] = 3 81 self.assertRaises(TypeError, _del) 82 self.assertRaises(TypeError, _set) 83 84 _dict = {} 85 def getitem(s, name): 86 return _dict[name] 87 def setitem(s, name, value): 88 _dict[name] = value 89 def delitem(s, name): 90 del _dict[name] 91 92 mock.__setitem__ = setitem 93 mock.__getitem__ = getitem 94 mock.__delitem__ = delitem 95 96 self.assertRaises(KeyError, lambda: mock['foo']) 97 mock['foo'] = 'bar' 98 self.assertEqual(_dict, {'foo': 'bar'}) 99 self.assertEqual(mock['foo'], 'bar') 100 del mock['foo'] 101 self.assertEqual(_dict, {}) 102 103 104 def test_numeric(self): 105 original = mock = Mock() 106 mock.value = 0 107 108 self.assertRaises(TypeError, lambda: mock + 3) 109 110 def add(self, other): 111 mock.value += other 112 return self 113 mock.__add__ = add 114 self.assertEqual(mock + 3, mock) 115 self.assertEqual(mock.value, 3) 116 117 del mock.__add__ 118 def iadd(mock): 119 mock += 3 120 self.assertRaises(TypeError, iadd, mock) 121 mock.__iadd__ = add 122 mock += 6 123 self.assertEqual(mock, original) 124 self.assertEqual(mock.value, 9) 125 126 self.assertRaises(TypeError, lambda: 3 + mock) 127 mock.__radd__ = add 128 self.assertEqual(7 + mock, mock) 129 self.assertEqual(mock.value, 16) 130 131 def test_division(self): 132 original = mock = Mock() 133 mock.value = 32 134 self.assertRaises(TypeError, lambda: mock / 2) 135 136 def truediv(self, other): 137 mock.value /= other 138 return self 139 mock.__truediv__ = truediv 140 self.assertEqual(mock / 2, mock) 141 self.assertEqual(mock.value, 16) 142 143 del mock.__truediv__ 144 def itruediv(mock): 145 mock /= 4 146 self.assertRaises(TypeError, itruediv, mock) 147 mock.__itruediv__ = truediv 148 mock /= 8 149 self.assertEqual(mock, original) 150 self.assertEqual(mock.value, 2) 151 152 self.assertRaises(TypeError, lambda: 8 / mock) 153 mock.__rtruediv__ = truediv 154 self.assertEqual(0.5 / mock, mock) 155 self.assertEqual(mock.value, 4) 156 157 def test_hash(self): 158 mock = Mock() 159 # test delegation 160 self.assertEqual(hash(mock), Mock.__hash__(mock)) 161 162 def _hash(s): 163 return 3 164 mock.__hash__ = _hash 165 self.assertEqual(hash(mock), 3) 166 167 168 def test_nonzero(self): 169 m = Mock() 170 self.assertTrue(bool(m)) 171 172 m.__bool__ = lambda s: False 173 self.assertFalse(bool(m)) 174 175 176 def test_comparison(self): 177 mock = Mock() 178 def comp(s, o): 179 return True 180 mock.__lt__ = mock.__gt__ = mock.__le__ = mock.__ge__ = comp 181 self. assertTrue(mock < 3) 182 self. assertTrue(mock > 3) 183 self. assertTrue(mock <= 3) 184 self. assertTrue(mock >= 3) 185 186 self.assertRaises(TypeError, lambda: MagicMock() < object()) 187 self.assertRaises(TypeError, lambda: object() < MagicMock()) 188 self.assertRaises(TypeError, lambda: MagicMock() < MagicMock()) 189 self.assertRaises(TypeError, lambda: MagicMock() > object()) 190 self.assertRaises(TypeError, lambda: object() > MagicMock()) 191 self.assertRaises(TypeError, lambda: MagicMock() > MagicMock()) 192 self.assertRaises(TypeError, lambda: MagicMock() <= object()) 193 self.assertRaises(TypeError, lambda: object() <= MagicMock()) 194 self.assertRaises(TypeError, lambda: MagicMock() <= MagicMock()) 195 self.assertRaises(TypeError, lambda: MagicMock() >= object()) 196 self.assertRaises(TypeError, lambda: object() >= MagicMock()) 197 self.assertRaises(TypeError, lambda: MagicMock() >= MagicMock()) 198 199 200 def test_equality(self): 201 for mock in Mock(), MagicMock(): 202 self.assertEqual(mock == mock, True) 203 self.assertIsInstance(mock == mock, bool) 204 self.assertEqual(mock != mock, False) 205 self.assertIsInstance(mock != mock, bool) 206 self.assertEqual(mock == object(), False) 207 self.assertEqual(mock != object(), True) 208 209 def eq(self, other): 210 return other == 3 211 mock.__eq__ = eq 212 self.assertTrue(mock == 3) 213 self.assertFalse(mock == 4) 214 215 def ne(self, other): 216 return other == 3 217 mock.__ne__ = ne 218 self.assertTrue(mock != 3) 219 self.assertFalse(mock != 4) 220 221 mock = MagicMock() 222 mock.__eq__.return_value = True 223 self.assertIsInstance(mock == 3, bool) 224 self.assertEqual(mock == 3, True) 225 226 mock.__ne__.return_value = False 227 self.assertIsInstance(mock != 3, bool) 228 self.assertEqual(mock != 3, False) 229 230 231 def test_len_contains_iter(self): 232 mock = Mock() 233 234 self.assertRaises(TypeError, len, mock) 235 self.assertRaises(TypeError, iter, mock) 236 self.assertRaises(TypeError, lambda: 'foo' in mock) 237 238 mock.__len__ = lambda s: 6 239 self.assertEqual(len(mock), 6) 240 241 mock.__contains__ = lambda s, o: o == 3 242 self.assertIn(3, mock) 243 self.assertNotIn(6, mock) 244 245 mock.__iter__ = lambda s: iter('foobarbaz') 246 self.assertEqual(list(mock), list('foobarbaz')) 247 248 249 def test_magicmock(self): 250 mock = MagicMock() 251 252 mock.__iter__.return_value = iter([1, 2, 3]) 253 self.assertEqual(list(mock), [1, 2, 3]) 254 255 getattr(mock, '__bool__').return_value = False 256 self.assertFalse(hasattr(mock, '__nonzero__')) 257 self.assertFalse(bool(mock)) 258 259 for entry in _magics: 260 self.assertTrue(hasattr(mock, entry)) 261 self.assertFalse(hasattr(mock, '__imaginary__')) 262 263 264 def test_magic_mock_equality(self): 265 mock = MagicMock() 266 self.assertIsInstance(mock == object(), bool) 267 self.assertIsInstance(mock != object(), bool) 268 269 self.assertEqual(mock == object(), False) 270 self.assertEqual(mock != object(), True) 271 self.assertEqual(mock == mock, True) 272 self.assertEqual(mock != mock, False) 273 274 def test_asyncmock_defaults(self): 275 mock = AsyncMock() 276 self.assertEqual(int(mock), 1) 277 self.assertEqual(complex(mock), 1j) 278 self.assertEqual(float(mock), 1.0) 279 self.assertNotIn(object(), mock) 280 self.assertEqual(len(mock), 0) 281 self.assertEqual(list(mock), []) 282 self.assertEqual(hash(mock), object.__hash__(mock)) 283 self.assertEqual(str(mock), object.__str__(mock)) 284 self.assertTrue(bool(mock)) 285 self.assertEqual(round(mock), mock.__round__()) 286 self.assertEqual(math.trunc(mock), mock.__trunc__()) 287 self.assertEqual(math.floor(mock), mock.__floor__()) 288 self.assertEqual(math.ceil(mock), mock.__ceil__()) 289 self.assertTrue(asyncio.iscoroutinefunction(mock.__aexit__)) 290 self.assertTrue(asyncio.iscoroutinefunction(mock.__aenter__)) 291 self.assertIsInstance(mock.__aenter__, AsyncMock) 292 self.assertIsInstance(mock.__aexit__, AsyncMock) 293 294 # in Python 3 oct and hex use __index__ 295 # so these tests are for __index__ in py3k 296 self.assertEqual(oct(mock), '0o1') 297 self.assertEqual(hex(mock), '0x1') 298 # how to test __sizeof__ ? 299 300 def test_magicmock_defaults(self): 301 mock = MagicMock() 302 self.assertEqual(int(mock), 1) 303 self.assertEqual(complex(mock), 1j) 304 self.assertEqual(float(mock), 1.0) 305 self.assertNotIn(object(), mock) 306 self.assertEqual(len(mock), 0) 307 self.assertEqual(list(mock), []) 308 self.assertEqual(hash(mock), object.__hash__(mock)) 309 self.assertEqual(str(mock), object.__str__(mock)) 310 self.assertTrue(bool(mock)) 311 self.assertEqual(round(mock), mock.__round__()) 312 self.assertEqual(math.trunc(mock), mock.__trunc__()) 313 self.assertEqual(math.floor(mock), mock.__floor__()) 314 self.assertEqual(math.ceil(mock), mock.__ceil__()) 315 self.assertTrue(asyncio.iscoroutinefunction(mock.__aexit__)) 316 self.assertTrue(asyncio.iscoroutinefunction(mock.__aenter__)) 317 self.assertIsInstance(mock.__aenter__, AsyncMock) 318 self.assertIsInstance(mock.__aexit__, AsyncMock) 319 320 # in Python 3 oct and hex use __index__ 321 # so these tests are for __index__ in py3k 322 self.assertEqual(oct(mock), '0o1') 323 self.assertEqual(hex(mock), '0x1') 324 # how to test __sizeof__ ? 325 326 327 def test_magic_methods_fspath(self): 328 mock = MagicMock() 329 expected_path = mock.__fspath__() 330 mock.reset_mock() 331 332 self.assertEqual(os.fspath(mock), expected_path) 333 mock.__fspath__.assert_called_once() 334 335 336 def test_magic_methods_and_spec(self): 337 class Iterable(object): 338 def __iter__(self): pass 339 340 mock = Mock(spec=Iterable) 341 self.assertRaises(AttributeError, lambda: mock.__iter__) 342 343 mock.__iter__ = Mock(return_value=iter([])) 344 self.assertEqual(list(mock), []) 345 346 class NonIterable(object): 347 pass 348 mock = Mock(spec=NonIterable) 349 self.assertRaises(AttributeError, lambda: mock.__iter__) 350 351 def set_int(): 352 mock.__int__ = Mock(return_value=iter([])) 353 self.assertRaises(AttributeError, set_int) 354 355 mock = MagicMock(spec=Iterable) 356 self.assertEqual(list(mock), []) 357 self.assertRaises(AttributeError, set_int) 358 359 360 def test_magic_methods_and_spec_set(self): 361 class Iterable(object): 362 def __iter__(self): pass 363 364 mock = Mock(spec_set=Iterable) 365 self.assertRaises(AttributeError, lambda: mock.__iter__) 366 367 mock.__iter__ = Mock(return_value=iter([])) 368 self.assertEqual(list(mock), []) 369 370 class NonIterable(object): 371 pass 372 mock = Mock(spec_set=NonIterable) 373 self.assertRaises(AttributeError, lambda: mock.__iter__) 374 375 def set_int(): 376 mock.__int__ = Mock(return_value=iter([])) 377 self.assertRaises(AttributeError, set_int) 378 379 mock = MagicMock(spec_set=Iterable) 380 self.assertEqual(list(mock), []) 381 self.assertRaises(AttributeError, set_int) 382 383 384 def test_setting_unsupported_magic_method(self): 385 mock = MagicMock() 386 def set_setattr(): 387 mock.__setattr__ = lambda self, name: None 388 self.assertRaisesRegex(AttributeError, 389 "Attempting to set unsupported magic method '__setattr__'.", 390 set_setattr 391 ) 392 393 394 def test_attributes_and_return_value(self): 395 mock = MagicMock() 396 attr = mock.foo 397 def _get_type(obj): 398 # the type of every mock (or magicmock) is a custom subclass 399 # so the real type is the second in the mro 400 return type(obj).__mro__[1] 401 self.assertEqual(_get_type(attr), MagicMock) 402 403 returned = mock() 404 self.assertEqual(_get_type(returned), MagicMock) 405 406 407 def test_magic_methods_are_magic_mocks(self): 408 mock = MagicMock() 409 self.assertIsInstance(mock.__getitem__, MagicMock) 410 411 mock[1][2].__getitem__.return_value = 3 412 self.assertEqual(mock[1][2][3], 3) 413 414 415 def test_magic_method_reset_mock(self): 416 mock = MagicMock() 417 str(mock) 418 self.assertTrue(mock.__str__.called) 419 mock.reset_mock() 420 self.assertFalse(mock.__str__.called) 421 422 423 def test_dir(self): 424 # overriding the default implementation 425 for mock in Mock(), MagicMock(): 426 def _dir(self): 427 return ['foo'] 428 mock.__dir__ = _dir 429 self.assertEqual(dir(mock), ['foo']) 430 431 432 @unittest.skipIf('PyPy' in sys.version, "This fails differently on pypy") 433 def test_bound_methods(self): 434 m = Mock() 435 436 # XXXX should this be an expected failure instead? 437 438 # this seems like it should work, but is hard to do without introducing 439 # other api inconsistencies. Failure message could be better though. 440 m.__iter__ = [3].__iter__ 441 self.assertRaises(TypeError, iter, m) 442 443 444 def test_magic_method_type(self): 445 class Foo(MagicMock): 446 pass 447 448 foo = Foo() 449 self.assertIsInstance(foo.__int__, Foo) 450 451 452 def test_descriptor_from_class(self): 453 m = MagicMock() 454 type(m).__str__.return_value = 'foo' 455 self.assertEqual(str(m), 'foo') 456 457 458 def test_iterable_as_iter_return_value(self): 459 m = MagicMock() 460 m.__iter__.return_value = [1, 2, 3] 461 self.assertEqual(list(m), [1, 2, 3]) 462 self.assertEqual(list(m), [1, 2, 3]) 463 464 m.__iter__.return_value = iter([4, 5, 6]) 465 self.assertEqual(list(m), [4, 5, 6]) 466 self.assertEqual(list(m), []) 467 468 469 def test_matmul(self): 470 m = MagicMock() 471 self.assertIsInstance(m @ 1, MagicMock) 472 m.__matmul__.return_value = 42 473 m.__rmatmul__.return_value = 666 474 m.__imatmul__.return_value = 24 475 self.assertEqual(m @ 1, 42) 476 self.assertEqual(1 @ m, 666) 477 m @= 24 478 self.assertEqual(m, 24) 479 480 def test_divmod_and_rdivmod(self): 481 m = MagicMock() 482 self.assertIsInstance(divmod(5, m), MagicMock) 483 m.__divmod__.return_value = (2, 1) 484 self.assertEqual(divmod(m, 2), (2, 1)) 485 m = MagicMock() 486 foo = divmod(2, m) 487 self.assertIsInstance(foo, MagicMock) 488 foo_direct = m.__divmod__(2) 489 self.assertIsInstance(foo_direct, MagicMock) 490 bar = divmod(m, 2) 491 self.assertIsInstance(bar, MagicMock) 492 bar_direct = m.__rdivmod__(2) 493 self.assertIsInstance(bar_direct, MagicMock) 494 495 # http://bugs.python.org/issue23310 496 # Check if you can change behaviour of magic methods in MagicMock init 497 def test_magic_in_initialization(self): 498 m = MagicMock(**{'__str__.return_value': "12"}) 499 self.assertEqual(str(m), "12") 500 501 def test_changing_magic_set_in_initialization(self): 502 m = MagicMock(**{'__str__.return_value': "12"}) 503 m.__str__.return_value = "13" 504 self.assertEqual(str(m), "13") 505 m = MagicMock(**{'__str__.return_value': "12"}) 506 m.configure_mock(**{'__str__.return_value': "14"}) 507 self.assertEqual(str(m), "14") 508 509 510if __name__ == '__main__': 511 unittest.main() 512