How do I unit test a monkey patch in Python
-
06-07-2021 - |
Вопрос
I have a utility method that behaves like this
def my_patch_method(self):
pass
def patch_my_lib():
from mylib import MyClass
MyClass.target_method = my_patch_method
return MyClass()
This test fails:
self.assertEqual(my_patch_method, patch_my_lib().target_method)
Whereas this one works:
self.assertEqual(my_patch_method.__name__, patch_my_lib().target_method.__name__)
As the patch method does not have the same name, this is still acceptable proof that patch_my_lib()
is doing what it's payed for but why doesn't the first work as I would expect ? And, is there a way to "fix" it ?
Решение
The reason your first test fails is that once you monkey-patch the function into your class, it isn't really the same object any more.
>>> def foo(self): pass
...
>>> class Foo: pass
...
>>> Foo.bar = foo
>>> type(Foo.bar)
<type 'instancemethod'>
>>> type(foo)
<type 'function'>
>>>
>>> Foo.bar is foo
False
>>> Foo.bar == foo
False
In fact, the original function and the new method have different types. Instead, have your first test check this condition:
>>> Foo.bar.im_func is foo
True
So maybe this: self.assertIs(my_patch_method, patch_my_lib().target_method.im_func)
Другие советы
Try:
self.assertEqual(my_patch_method, patch_my_lib().target_method.im_func)
You are returning an instance from patch_my_lib, so comparing the function to the bound method
Something like this should pass
self.assertEqual(my_patch_method, patch_my_lib().target_method.im_func)
But it's probably better to check that the behaviour you are patching is working
MyClass.target_method = my_patch_method
sets your function as a class function for MyClass
, but you return a instance of that class with return MyClass()
.