run - python function inside a function
EjecuciĆ³n de pruebas unitarias en funciones anidadas (6)
inner no existe hasta que lo hace el exterior. Debería moverse hacia arriba a una función de nivel superior para probarla, o hacer que la prueba externa pruebe todas las rutas de ejecución posibles de sí mismo e internas.
Tenga en cuenta que la función interna no es una función simple, es un cierre. Considera este caso:
def outer(a):
b = compute_something_from(a)
def inner():
do_something_with(a, b)
Esa es la compensación de la capacidad de prueba estándar. Si su complejidad ciclomática es demasiado alta, sus pruebas serán demasiado numerosas.
Vengo del mundo de Java, donde puedes ocultar variables y funciones y luego ejecutar pruebas unitarias contra ellos usando la reflexión. He utilizado funciones anidadas para ocultar los detalles de implementación de mis clases para que solo la API pública esté visible. Estoy intentando escribir pruebas unitarias contra estas funciones anidadas para asegurarme de que no las rompo a medida que desarrollo. He intentado llamar a una de las funciones anidadas como:
def outer():
def inner():
pass
outer.inner()
que da como resultado el mensaje de error:
AttributeError: el objeto ''function'' no tiene atributo ''inner''
¿Hay alguna forma de escribir pruebas unitarias contra estas funciones anidadas? Si no, ¿hay alguna manera de activar el nombre de munging para los nombres de las funciones como se puede para las variables de la clase prefijando con __?
La convención de Python es para nombrar funciones y métodos "privados" con un subrayado inicial. Cuando ve un subrayado inicial, sabe que no debe intentarlo.
Recuerde, Python no es Java .
No creo que haya ninguna posibilidad de acceder a inner () desde el espacio de nombres externo.
Sin embargo, en mi opinión, el hecho de que usted mantenga inner () anidado implica que el único "contrato" que realmente importa es el externo (). inner () es parte de la implementación y no debería probar la implementación. Si realmente quieres probar inner (), haz pruebas extensas en outer () con datos que involucrarán todas las funcionalidades de inner ().
No hay manera de obtener la función interna desde el objeto de función externo (ver las otras respuestas!). Sin embargo, tanto las pruebas unitarias como los cierres han hecho (al menos para mí) increíbles mejoras en el rendimiento del desarrollador. Podemos tener ambos? ¿Podemos probar funciones anidadas de forma aislada?
No es fácil.
Sin embargo, esto podría lograrse aparentemente con el uso de módulos de Python analizador, ast o tokenizador para dividir el código en sí mismo, extraer funciones internas (por algún camino a través del anidamiento) y permitir que las pruebas las ejecuten con el estado de las funciones adjuntas (valores para nombres cerrados) y stubs / mocks para funciones más anidadas (definidas dentro del objetivo de prueba).
Alguien sabe de algo como esto? Google no pudo encontrar nada.
Tenía la misma duda y encontré una forma de hacer pruebas para funciones internas.
def outer():
def inner():
pass
if __debug__:
test_inner(inner)
# return
def test_inner(f):
f() # this calls the inner function
outer()
Básicamente puede enviar la función interna como un parámetro al exterior y probarla como lo desee. Al llamar a outer () , se ejecutará la prueba y, dado que se trata de un cierre, conservará cualquier propiedad adicional de la función externa (como las variables). Usando una lista, puede enviar tantas funciones como desee. Para ignorar el if , una opción es ejecutar el código de esa manera:
python -O code.py
He escrito un pequeño módulo de ayuda que permite exactamente esto:
Ejemplos de funciones anidadas:
def f(v1):
v2 = 1
def g(v3=2):
return v1 + v2 + v3 + 4
def h():
return 16
return g() + h() + 32
class C(object):
def foo(self):
def k(x):
return [ self, x ]
return k(3)
def m():
vm = 1
def n(an=2):
vn = 4
def o(ao=8):
vo = 16
return vm + an + vn + ao + vo
return o()
return n()
Estos se pueden probar en unidades usando este tipo de código:
import unittest
from nested import nested
class TestNested(unittest.TestCase):
def runTest(self):
nestedG = nested(f, ''g'', v1=8, v2=1)
self.assertEqual(nestedG(2), 15)
nestedH = nested(f, ''h'')
self.assertEqual(nestedH(), 16)
nestedK = nested(C.foo, ''k'', self=''mock'')
self.assertEqual(nestedK(5), [ ''mock'', 5 ])
nestedN = nested(m, ''n'', vm=1)
nestedO = nested(nestedN, ''o'', vm=1, an=2, vn=4)
self.assertEqual(nestedO(8), 31)
def main(argv):
unittest.main()
if __name__ == ''__main__'':
import sys
sys.exit(main(sys.argv))
El módulo pequeño auxiliar nested
ve así:
import types
def freeVar(val):
def nested():
return val
return nested.__closure__[0]
def nested(outer, innerName, **freeVars):
if isinstance(outer, (types.FunctionType, types.MethodType)):
outer = outer.func_code
for const in outer.co_consts:
if isinstance(const, types.CodeType) and const.co_name == innerName:
return types.FunctionType(const, globals(), None, None, tuple(
freeVar(freeVars[name]) for name in const.co_freevars))