How do you make a Python class which subclasses Mock, to extend the base Mock class with some features specific to one class from your code?
Like this, right?
class MyClass(mock.Mock): def __init__(self, param1, param2): super(MyClass, self).__init__() def real_implementation_of_something(...): ...
This is useful when you want most methods to be mocks but there is some functionality that still needs to be there, or at least can’t be mocked automatically by the Mock class. Sadly, though, when you call any of its methods you get the following cryptic error:
def _get_child_mock(self, **kw): """Create the child mocks for attributes and return value. By default child mocks will be the same type as the parent. Subclasses of Mock may want to override this to customize the way child mocks are made. For non-callable mocks the callable variant will be used (rather than any custom subclass).""" _type = type(self) if not issubclass(_type, CallableMixin): if issubclass(_type, NonCallableMagicMock): klass = MagicMock elif issubclass(_type, NonCallableMock) : klass = Mock else: klass = _type.__mro__ > return klass(**kw) E TypeError: __init__() got an unexpected keyword argument 'param1'
The first time you call a certain method on a Mock, what the object does is dynamically create another Mock object to represent the method, and save that as an attribute. My mental model of Mock was for a long time that you mocked objects, but that’s not the right way to look at it. A Mock can represent anything (if you’ve been paying attention you’ll remember that everything in Python is an object).
The problem above is that when you access MyClass.foo(), the Mock library calls the constructor MyClass.__init__() again to create a mock that represents foo. It passed in various arguments for Mock.__init__() class, but because we have subclassed Mock and overridden the constructor, this call went to MyClass.__init__() first, which choked on the unexpected parameters and gave us the weird backtrace you see above.
The fix is kind of obvious when you think about it:
class MyClass(mock.NonCallableMock): def __init__(self, param1, param2): super(MyClass, self).__init__() def real_implementation_of_something(...): ...