• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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