A veces, las funciones privadas de un módulo o clase son simplemente unidades internas de funcionalidad aún por extraer, que podrían merecer sus propias pruebas. Entonces, ¿por qué no probarlos? Nos vamos a escribir pruebas para ellos más adelante si / cuando se extraen. Entonces, ¿por qué no escribir las pruebas ahora, cuando todavía forman parte del mismo archivo?
Demostrar:
Primero escribí module_a
. Ahora quiero escribir pruebas para ello. Me gustaría probar la función 'privada' _private_func
. No entiendo por qué no escribiría una prueba para él, si más tarde podría refactorizarlo en su propio módulo interno de todos modos, y luego escribir pruebas para él.
Supongamos que tengo un módulo con las siguientes funciones (también podría ser una clase):
def public_func(a):
b = _do_stuff(a)
return _do_more_stuff(b)
_do_stuff
y _do_more_stuff
son funciones 'privadas' del módulo.
Entiendo la idea de que solo debemos probar la interfaz pública, no los detalles de implementación. Sin embargo, aquí está la cosa:
_do_stuff
y _do_more_stuff
contienen la mayoría de la funcionalidad del módulo. Cada uno de ellos podría ser una función pública de un módulo 'interno' diferente. Pero aún no han evolucionado y son lo suficientemente grandes como para extraerse para separar archivos.
Por lo tanto, probar estas funciones se siente bien porque son unidades importantes de funcionalidad. Si estuvieran en diferentes módulos como funciones públicas, los habríamos probado. Entonces, ¿por qué no probarlos cuando aún no están (o nunca) extraídos en un archivo diferente?
Respuestas:
La necesidad de probar no es lo mismo que la necesidad de ser público.
El código no trivial necesita pruebas independientemente de la exposición. El comportamiento no público no necesita existir y mucho menos ser probado.
Estas opiniones en conflicto pueden llevarlo a querer hacer públicas todas las funciones o negarse a descomponer el código en una función a menos que sea pública.
Esta no es la respuesta. Esté dispuesto a crear funciones de ayuda privadas. Pruébelos a través de la interfaz pública que lo utiliza tanto como sea posible.
Si las pruebas a través de la interfaz pública no ejercen la función privada lo suficiente, la función privada intenta permitir demasiado.
La validación puede ayudar a reducir lo que permite la función privada. Si no puede pasar un valor nulo a través de la interfaz pública, aún puede lanzar una excepción si aparece de todos modos.
¿Por qué deberías? ¿Por qué probar lo que nunca verás? Porque las cosas cambian. Puede ser privado ahora pero público después. El código de llamada podría cambiar. El código que rechaza explícitamente nulo deja en claro el uso adecuado y el estado esperado.
Por supuesto, nulo podría estar bien. Es solo un ejemplo aquí. Pero si espera algo, es útil dejar en claro esa expectativa.
Es posible que ese no sea el tipo de prueba que tenía en mente, pero con suerte estará dispuesto a crear funciones de ayuda privadas cuando sea apropiado.
El deseo de probar es bueno, pero no debería ser la fuerza impulsora en el diseño de su API pública. Diseñe la API pública para que sea fácil de usar. Es probable que no lo sea si todas las funciones son públicas. La API debería ser algo que las personas puedan entender cómo usar sin sumergirse en el código. No dejes que esas personas se pregunten para qué sirve esta extraña función auxiliar.
Ocultar funciones de ayuda pública en un módulo interno es un intento de respetar la necesidad de una API limpia al tiempo que expone a los ayudantes para las pruebas. No diré que esto está mal. Es posible que esté dando el primer paso hacia una capa arquitectónica diferente. Pero, por favor, domine el arte de probar las funciones de ayuda privadas a través de las funciones públicas que las usan primero. De esa manera, no usarás demasiado esta solución.
fuente
Respuesta corta: no
Respuesta más larga: sí, pero a través de la 'API' pública de su clase
La idea general de los miembros privados de una clase es que representan una funcionalidad que debería ser invisible fuera de la 'unidad' de código, por grande que sea la definición de esa unidad. En el código orientado a objetos, esa unidad a menudo termina siendo una clase.
Debe tener su clase diseñada de modo que sea posible invocar toda la funcionalidad privada a través de varias combinaciones de estado de entrada. Si encuentra que no hay una forma relativamente directa de hacer esto, probablemente sea una pista de que su diseño necesita más atención.
Después de aclarar la pregunta, esto es solo una cuestión de semántica. Si el código en cuestión puede funcionar como una unidad independiente separada, y se está probando como si fuera un código público, no puedo ver ningún beneficio de no moverlo a un módulo independiente. En la actualidad, solo sirve para confundir a los futuros desarrolladores (incluido usted, dentro de 6 meses), en cuanto a por qué el código aparentemente público está oculto dentro de otro módulo.
fuente
El objetivo de las funciones privadas es que son detalles de implementación ocultos que se pueden cambiar a voluntad, sin cambiar la API pública. Para su código de ejemplo:
Si tiene una serie de pruebas que solo usa
public_func
, entonces si la reescribe para:entonces, siempre y cuando el resultado de retorno para un valor particular de
a
permanezca igual, entonces todas sus pruebas serán buenas. Si el resultado devuelto cambia, una prueba fallará, destacando el hecho de que algo se rompió.Todo esto es algo bueno: API pública estática; funcionamiento interno bien encapsulado; y pruebas robustas.
Sin embargo, si hubiera escrito pruebas para
_do_stuff
o_do_more_stuff
y luego hubiera realizado el cambio anterior, ahora tendría un montón de pruebas rotas, no porque la funcionalidad cambiara, sino porque la implementación de esa funcionalidad cambió. Esas pruebas necesitarían reescribirse para funcionar con las nuevas funciones, pero una vez que estén funcionando, todo lo que sabría es que esas pruebas funcionaron con las nuevas funciones. Habría perdido las pruebas originales y, por lo tanto, no sabría si el comportamiento depublic_func
ha cambiado y, por lo tanto, sus pruebas serían básicamente inútiles.Esto es algo malo: una API cambiante; funcionamiento interno expuesto estrechamente acoplado a las pruebas; y pruebas frágiles que cambian tan pronto como se realizan cambios en la implementación.
Entonces no, no pruebe las funciones privadas. Siempre.
fuente