'Why can't dunder/magic methods be set in unittest.mock.Mock.configure_mock?
I was writing some unit test in python and needed to mock a very general collections.abc.Sized, so I set off creating a Mock with a __len__
method whose return value is any int I want.
from unittest.mock import Mock
sized = Mock(**{"__len__.return_value": 8})
Which failed with AttributeErrorgave: __len__
and produced the traceback at the end of the post, while the following works:
from unittest.mock import Mock
sized = Mock()
sized.__len__.return_value = 8
# or
from unittest.mock import MagicMock
sized = MagicMock(**{"__len__.return_value": 8})
Reading down the traceback we see that:
- CallableMixin's
__init__
is called. - kwargs passed to Mock's
__init__
method get passed toMock.configure_mock()
- the kwargs name is
getattr()
ed on the Mock itself - Mock
__getattr__
method raises an AttributeError if attribute name is magic, that is if'__%s__' % name[2:-2] == name
.
This seems like a very arbitrary limitation and I wonder if there is a reason for Mock not to accept magic methods in Mock.configure_mock()
.
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Input In [2], in <cell line: 1>()
----> 1 Mock(**{"__len__.return_value": 0})
File ~/.pyenv/versions/3.10.3/lib/python3.10/unittest/mock.py:1086, in CallableMixin.__init__(self, spec, side_effect, return_value, wraps, name, spec_set, parent, _spec_state, _new_name, _new_parent, **kwargs)
1082 def __init__(self, spec=None, side_effect=None, return_value=DEFAULT,
1083 wraps=None, name=None, spec_set=None, parent=None,
1084 _spec_state=None, _new_name='', _new_parent=None, **kwargs):
1085 self.__dict__['_mock_return_value'] = return_value
-> 1086 _safe_super(CallableMixin, self).__init__(
1087 spec, wraps, name, spec_set, parent,
1088 _spec_state, _new_name, _new_parent, **kwargs
1089 )
1091 self.side_effect = side_effect
File ~/.pyenv/versions/3.10.3/lib/python3.10/unittest/mock.py:457, in NonCallableMock.__init__(self, spec, wraps, name, spec_set, parent, _spec_state, _new_name, _new_parent, _spec_as_instance, _eat_self, unsafe, **kwargs)
454 __dict__['_mock_unsafe'] = unsafe
456 if kwargs:
--> 457 self.configure_mock(**kwargs)
459 _safe_super(NonCallableMock, self).__init__(
460 spec, wraps, name, spec_set, parent,
461 _spec_state
462 )
File ~/.pyenv/versions/3.10.3/lib/python3.10/unittest/mock.py:625, in NonCallableMock.configure_mock(self, **kwargs)
623 obj = self
624 for entry in args:
--> 625 obj = getattr(obj, entry)
626 setattr(obj, final, val)
File ~/.pyenv/versions/3.10.3/lib/python3.10/unittest/mock.py:636, in NonCallableMock.__getattr__(self, name)
634 raise AttributeError("Mock object has no attribute %r" % name)
635 elif _is_magic(name):
--> 636 raise AttributeError(name)
637 if not self._mock_unsafe:
638 if name.startswith(('assert', 'assret', 'asert', 'aseert', 'assrt')):
AttributeError: __len__
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|