¿Cómo burlarse de las funciones anidadas?

La biblioteca burlona que uso es … simulacro .

Encontré este problema de “funciones anidadas simuladas” cuando intenté escribir un caso de prueba para una función (código heredado).

Esta función utiliza una función anidada muy compleja con grandes dependencias en otros módulos.

Me pregunto si es posible simular funciones anidadas con mock .

por ejemplo, debe simular llamadas de función anidadas (funciones encadenadas) desde Google DRIVE API

 result = get_drive_service().files().insert(body='body', convert=True).execute() 

por lo que necesita parchear a través de las funciones: service_mock (), files (), insert (), hasta la última ejecución () respuesta:

 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} 

Esquema principal: primero. return_value .second. return_value .third. return_value .last. return_value = rsp

Una opción es cambiar su función para que opcionalmente acepte la función a la que llamar, por ejemplo, si tiene:

 def fn_to_test(): def inner_fn(): return 1 return inner_fn() + 3 

Cambiarlo a:

 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 

Luego, los usos “reales” obtendrán la función interna correcta, y en tus pruebas puedes proporcionar la tuya.

 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 

También podrías hacer esto:

 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 

De esta manera usted acaba de definir la anulación:

 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 

La única forma en que he visto hacer esto es crear dinámicamente una copia de su función externa, modificando las constantes del objeto de código de la función con el código para su función simulada:

¿Existe un equivalente de anulación para funciones anidadas?

¿Estás tratando de reemplazar una función anidada con un objeto simulado? Si es así, eso es bastante sencillo, sin importar cuán complicada sea la función. Puedes usar un MagicMock para reemplazar casi cualquier objeto de Python.

Si necesita simular una función que devuelve algo, simplemente puede configurar el MagicMock del MagicMock . Se vería algo como esto:

 >>> super_nested_mock = mock.MagicMock() >>> super_nested_mock.return_value = 42 >>> super_nested_mock() 42 

Sin embargo, si está intentando probar otra pieza de código que llama a su función super_nested algún lugar dentro y quiere super_nested , deberá usar un parche . En la biblioteca simulada, se verá algo como esto:

 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 

Aquí, cualquier elemento en el bloque with que normalmente llamaría super_nested llamará a super_nested_mock y simplemente devolverá el valor que configuró.

Hay algo de sutileza en lo que necesita poner exactamente en la llamada del parche. Principalmente, desea parchear el objeto como lo vería el módulo que está probando. Consulte ” dónde colocar el parche ” para obtener más instrucciones.