Как издеваться над вложенными функциями?
Издевательская библиотека, которую я использую, является... mock.
Я столкнулся с этой проблемой "ложных вложенных функций", когда пытался написать тестовый пример для функции (устаревший код).
Эта функция использовала очень сложную вложенную функцию с большими зависимостями от других модулей.
Интересно, можно ли издеваться над вложенными функциями с помощью mock
.
Ответы
Ответ 1
Например, вам нужно высмеять вложенные вызовы функций (связанные функции) из API Google DRIVE
result = get_drive_service().files().insert(body='body', convert=True).execute()
поэтому вам необходимо выполнить патчи через функции: service_mock(), files(), insert(), до последнего выполнения():
from mock import patch
with patch('path.to.import.get_drive_service') as service_mock:
service_mock.return_value.files.return_value.insert.\
return_value.execute.return_value = {'key': 'value', 'status': 200}
Основная схема:
return_value.second. return_value.third. return_value.last. return_value= rsp
Ответ 2
Один из вариантов - изменить вашу функцию, чтобы она могла принимать функцию для вызова, например. если у вас есть:
def fn_to_test():
def inner_fn():
return 1
return inner_fn() + 3
Измените его на:
def fn_to_test( inner_fn = null )
def inner_fn_orig():
return 1
if inner_fn==null:
inner_fn = inner_fn_orig
return fn() + 3
Тогда "реальные" использования получат правильную внутреннюю функцию, а в ваших тестах вы можете предоставить свои собственные.
fn_to_test() # calls the real inner function
def my_inner_fn():
return 3
fn_to_test( inner_fn=my_inner_fn ) # calls the new version
Вы также можете сделать это:
def fn_to_test():
def inner_fn_orign():
return 1
inner_fn = inner_fn_orig
try:
inner_fn = fn_to_test.inner_fn
excecpt AttributeError:
pass
return inner_fn() + 3
Таким образом вы просто определяете переопределение:
fn_to_test() # calls the real inner function
def my_inner_fn():
return 3
fn_to_test.inner_fn = my_inner_fn
fn_to_test() # calls the new version
Ответ 3
Вы пытаетесь заменить вложенную функцию макетным объектом? Если да, то это довольно просто, независимо от того, насколько сложна функция. Вы можете использовать MagicMock, чтобы заменить практически любой объект python.
Если вам нужно смоделировать функцию, которая возвращает что-то, вы можете просто установить параметр MagicMock
return_value
. Он будет выглядеть примерно так:
>>> super_nested_mock = mock.MagicMock()
>>> super_nested_mock.return_value = 42
>>> super_nested_mock()
42
Однако, если вы пытаетесь протестировать другой фрагмент кода, который вызывает вашу функцию super_nested
где-то внутри, и вы хотите издеваться над этим, вам нужно использовать patch. В макетной библиотеке он будет выглядеть примерно так:
with patch('super_nested') as super_nested_mock:
super_nested_mock.return_value = "A good value to test with"
assert my_function_that_calls_super_nested(5) == 20
Здесь все в блоке with
, который обычно вызывает super_nested
, будет вызывать super_nested_mock
и просто вернуть значение, которое вы ему установили.
Есть какая-то тонкость в том, что именно вам нужно включить в вызов патча. В основном, вы хотите исправить объект, поскольку модуль, который вы тестируете, увидит его. См. " где исправлять" для получения дополнительной инструкции.
Ответ 4
Единственный способ, которым я это видел, - это динамически создать копию вашей внешней функции, модифицируя константы объекта кода функции с помощью кода для вашей издеваемой функции:
Существует ли эквивалент переопределения для вложенных функций?