Contexto:
Actualmente estoy trabajando en un pequeño proyecto en Python. Comúnmente estructuro mis clases con algunos métodos públicos que están documentados pero que tratan principalmente con los conceptos de alto nivel (lo que un usuario de la clase debe saber y usar), y un montón de métodos ocultos (comenzando con guiones bajos) que están a cargo de procesamiento complejo o de bajo nivel.
Sé que las pruebas son esenciales para dar confianza en el código y para garantizar que cualquier modificación posterior no haya roto el comportamiento anterior.
Problema:
Para construir los métodos públicos de nivel superior sobre una base confiable, generalmente pruebo los métodos privados. Me resulta más fácil encontrar si una modificación de código ha introducido regresiones y dónde. Significa que esas pruebas internas pueden infringir revisiones menores y deberán ser reparadas / reemplazadas
Pero también sé que el método privado de pruebas unitarias es al menos un concepto en disputa o más a menudo considerado como una mala práctica. La razón es: solo se debe probar el comportamiento público ( ref. )
Pregunta:
Me importa seguir las mejores prácticas y me gustaría entender:
- ¿por qué es malo usar pruebas unitarias en métodos privados / ocultos (cuál es el riesgo)?
- ¿Cuáles son las mejores prácticas cuando los métodos públicos pueden usar procesamiento de bajo nivel y / o complejo?
Precisiones
- no es una forma de pregunta. Python no tiene un verdadero concepto de privacidad y los métodos ocultos simplemente no se enumeran, pero se pueden usar cuando se conoce su nombre
- Nunca me han enseñado reglas y patrones de programación: mis últimas clases son de los años 80 ... Aprendí idiomas principalmente por prueba y fracaso y referencias en Internet (Stack Exchange fue mi favorito durante años)
fuente
Respuestas:
Un par de razones:
Por lo general, cuando se siente tentado a probar el método privado de una clase, es un olor a diseño (clase iceberg, no hay suficientes componentes públicos reutilizables, etc.). Casi siempre hay algún problema "mayor" en juego.
Puede probarlos a través de la interfaz pública (que es cómo desea probarlos, porque así es como los llamará / usará el cliente). Puede obtener una falsa sensación de seguridad al ver la luz verde en todas las pruebas de aprobación de sus métodos privados. Es mucho mejor / más seguro probar casos extremos en sus funciones privadas a través de su interfaz pública.
Corre el riesgo de una duplicación de prueba severa (pruebas que se ven / se sienten muy similares) al probar métodos privados. Esto tiene consecuencias importantes cuando cambian los requisitos, ya que se romperán muchas más pruebas de las necesarias. También puede ponerlo en una posición en la que es difícil refactorizar debido a su conjunto de pruebas ... lo cual es la ironía final, ¡porque el conjunto de pruebas está ahí para ayudarlo a rediseñar y refactorizar de manera segura!
Un consejo si todavía está tentado a probar las partes privadas (no lo use si le molesta a usted y a YMMV, pero me ha funcionado bien en el pasado): a veces escribir pruebas unitarias para funciones privadas solo para asegurarse están trabajando exactamente como crees que pueden ser valiosos (especialmente si eres nuevo en un idioma). Sin embargo, una vez que esté seguro de que funcionan, elimine las pruebas y asegúrese siempre de que las pruebas públicas sean sólidas y se detendrán si alguien realiza un cambio atroz en dicha función privada.
Cuándo probar métodos privados: dado que esta respuesta se ha vuelto (algo) popular, me siento obligado a mencionar que una "mejor práctica" es siempre eso: una "mejor práctica". No significa que debas hacerlo de manera dogmática o ciega. Si cree que debe probar sus métodos privados y tiene una razón legítima (como si estuviera escribiendo pruebas de caracterización para una aplicación heredada), pruebe sus métodos privados . Las circunstancias específicas siempre prevalecen sobre cualquier regla general o práctica recomendada. Solo tenga en cuenta algunas de las cosas que pueden salir mal (ver arriba).
Tengo una respuesta que detalla esto en SO que no repetiré aquí: /programming/105007/should-i-test-private-methods-or-only-public-ones/ 47401015 # 47401015
fuente
bin_search(arr, item)
(público) ybin_search(arr, item, low, hi)
(privado, hay muchas formas de hacer una búsqueda de bin), entonces todo lo que necesitas probar es el público que se enfrenta a uno (bin_search(arr, item)
)Dado que uno de los propósitos principales de las pruebas unitarias es que puede refactorizar las partes internas de su programa y luego poder verificar que no ha roto su funcionalidad, es contraproducente si sus pruebas unitarias operan con un nivel de granularidad tan fino que Cualquier cambio en el código del programa requiere que reescriba sus pruebas.
fuente
Escribir pruebas unitarias para métodos privados vincula sus pruebas unitarias a los detalles de implementación.
Las pruebas unitarias deben probar el comportamiento de una clase en la superficie externa de la clase (es API pública). Las pruebas unitarias no deberían tener que saber nada sobre las entrañas de una clase. Escribir pruebas unitarias contra los detalles de implementación de una clase ata tus manos cuando llega el momento de refactorizar. Refactorizar seguramente romperá esas pruebas, porque no son parte de su API estable.
Dicho esto, ¿por qué puede ser que usted desee escribir pruebas unitarias para sus métodos privados?
Existe una tensión natural entre las pruebas unitarias y el desarrollo incremental. Los desarrolladores de software que usan un REPL (bucle read-eval-print) pueden dar fe de cuán productivo puede ser escribir y probar rápidamente pequeños bits de funcionalidad a medida que "crecen" una clase o función. La única buena manera de hacerlo en entornos que están basados en pruebas unitarias es escribir pruebas unitarias para métodos privados, pero hay mucha fricción al hacerlo. Las pruebas unitarias tardan en redactarse, necesita un método real contra el cual realizar pruebas y su marco de pruebas debe admitir la capacidad de mantener el método privado para que no contamine su API externa.
Algunos ecosistemas como C # y .NET tienen formas de crear entornos similares a REPL (herramientas como Linqpad hacen esto), pero su utilidad es limitada porque no tiene acceso a su proyecto. La ventana inmediata en Visual Studio es inconveniente; todavía no tiene Intellisense completo, debe usar nombres completos y desencadena una compilación cada vez que lo usa.
fuente
Según mi experiencia, descubrí que la unidad que prueba las clases internas, los métodos generalmente significa que tengo que eliminar las funciones probadas, las clases. Para crear otro nivel de abstracción.
Esto conduce a una mejor adhesión del Principio de Responsabilidad Única.
fuente
Creo que esta es una buena pregunta porque expone un problema común en las pruebas de cobertura. Pero una buena respuesta debe decirle que la cuestión no es exactamente correcto, porque, en teoría, debería no ser capaz de probar la unidad privadas métodos. Por eso son privados .
Tal vez una mejor pregunta sería "¿Qué debo hacer cuando quiero probar métodos privados?" , y la respuesta es bastante obvia: debe exponerlos de una manera que haga posible la prueba. Ahora, esto no significa necesariamente que debas hacer público el método y eso es todo. Lo más probable es que quieras hacer una mayor abstracción; muévase a una biblioteca o API diferente para que pueda hacer sus pruebas en esa biblioteca, sin exponer esa funcionalidad en su API principal.
Recuerde que hay una razón por la cual sus métodos tienen diferentes niveles de accesibilidad, y siempre debe pensar en cómo se utilizarán sus clases al final.
fuente