Как я могу модульно протестировать патч обезьяны в Python


У меня есть полезный метод, который ведет себя так

def my_patch_method(self):
    pass

def patch_my_lib():
    from mylib import MyClass
    MyClass.target_method = my_patch_method
    return MyClass()

Этот тест не проходит:

self.assertEqual(my_patch_method, patch_my_lib().target_method)

В то время как этот работает:

self.assertEqual(my_patch_method.__name__, patch_my_lib().target_method.__name__)

Поскольку метод патча не имеет такого же названия, это все еще приемлемое доказательство того, что patch_my_lib() делает то, за что он платит, но почему первый не работает так, как я ожидал бы ? И есть ли способ "исправить" это ?

4 4

4 ответа:

Причина, по которой ваш первый тест не проходит, заключается в том, что, как только вы вставляете функцию в свой класс, это уже не тот же самый объект.

>>> 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
На самом деле исходная функция и новый метод имеют разные типы. Вместо этого пусть ваш первый тест проверит это условие:
>>> Foo.bar.im_func is foo
True

Так, может быть, это: self.assertIs(my_patch_method, patch_my_lib().target_method.im_func)

Попробуйте:

self.assertEqual(my_patch_method, patch_my_lib().target_method.im_func)

Вы возвращаете экземпляр из patch_my_lib, поэтому сравнение функции с привязанным методом

Что-то вроде этого должно пройти

self.assertEqual(my_patch_method, patch_my_lib().target_method.im_func)

Но, вероятно, лучше проверить, что поведение, которое вы исправляете, работает

MyClass.target_method = my_patch_method задает функцию в качестве функции класса для MyClass, но вы возвращаете экземпляр этого класса с помощью return MyClass().