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