Условное издевательство: вызвать исходную функцию, если условие соответствует
Как я могу условно вызвать оригинальный метод в макете?
В этом примере я хочу только подделать возвращаемое значение, если bar=='x'
. В противном случае я хочу вызвать оригинальный метод.
def mocked_some_method(bar):
if bar=='x':
return 'fake'
return some_how_call_original_method(bar)
with mock.patch('mylib.foo.some_method', mocked_some_method):
do_some_stuff()
Я знаю, что это немного странно. Если я хочу подделать mylib.foo.some_method
в сторону do_some_stuff()
, это должно быть без условий. Все (не некоторые) звонки на some_method
должны быть осмеяны.
В моем случае это интеграционный тест, а не крошечный юнит-тест, а mylib.foo.some_method
является своего рода диспетчером, который очень часто используется. И в одном случае мне нужно подделать результат.
Обновление
Я написал этот вопрос четыре года назад. Сегодня очень странно делать условные насмешки. Издеваться надо только в тестах. Тесты (и производственный код) должны быть простыми и небольшими. Тесты должны быть безусловными. Когда я писал этот вопрос, мы все еще использовали огромные методы производства и длительные испытания. Сегодня я следую этим правилам (простые методы, безусловные тесты...). Я записал свои выводы: мои рекомендации по программированию
Ответы
Ответ 1
Если вам нужно просто поменять поведение, не заботясь о функции moker calls assert, вы можете использовать аргумент new
; в противном случае вы можете использовать side_effect
, которые могут быть вызваны.
Я предполагаю, что some_method
- это метод объекта (вместо staticmethod
), поэтому вам нужна ссылка на его объект, чтобы вызвать его. Ваша оболочка должна объявить в качестве первого аргумента объект и ваш патч использовать autospec=True
для использования правильной сигнатуры для случая side_effect
.
Заключительный трюк - это сохранить исходную ссылку на метод и использовать его для совершения вызова.
orig = mylib.foo.some_method
def mocked_some_method(self, bar):
if bar=='x':
return 'fake'
return orig(self, bar)
#Just replace:
with mock.patch('mylib.foo.some_method', new=mocked_some_method):
do_some_stuff()
#Replace by mock
with mock.patch('mylib.foo.some_method', side_effect=mocked_some_method, autospec=True) as mock_some_method:
do_some_stuff()
assert mock_some_method.called