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