This scripts fails:
import mock
class MyClass(object):
@classmethod
def my_method(cls):
print('my_method')
def mocked_method(cls):
print('I want this method to get called')
with mock.patch.object(MyClass, 'my_method', mocked_method):
MyClass.my_method()
Exception:
Traceback (most recent call last):
File "/home/foo/tmp/test_mocking_classmethod.py", line 14, in <module>
MyClass.my_method()
TypeError: unbound method mocked_method() must be called with MyClass instance as first argument (got nothing instead)
Python functions are descriptors and Python binds these to the instance they are looked up on, or in the case of classmethod
, to the class. Because you didn't use the classmethod
decorator on the replacement function, it is being bound wrongly (as a regular method instead, so no cls
is being passed in).
Simply wrap the target in a classmethod
decorator manually:
with mock.patch.object(MyClass, 'my_method', classmethod(mocked_method)):
MyClass.my_method()
Here I applied the @classmethod
decorator manually, but you could also just use it as intended, as a decorator, directly on the target function:
@classmethod
def mocked_method(cls):
print('I want this method to get called')
with mock.patch.object(MyClass, 'my_method', mocked_method):
MyClass.my_method()
Demo:
>>> import mock
>>> class MyClass(object):
... @classmethod
... def my_method(cls):
... print('my_method')
...
>>> def mocked_method(cls):
... print('I want this method to get called')
...
>>> with mock.patch.object(MyClass, 'my_method', classmethod(mocked_method)):
... MyClass.my_method()
...
I want this method to get called
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With