Sé que se supone que no debes probar métodos privados, y si parece que lo necesitas, es posible que haya una clase allí esperando para salir.
Pero, no quiero tener un millón de clases solo para poder probar sus interfaces públicas y encuentro que para muchas clases si solo pruebo los métodos públicos termino teniendo que burlarme de muchas dependencias y las pruebas unitarias son enorme y difícil de seguir.
Prefiero burlarme de los métodos privados cuando pruebo los públicos, y burlarme de las dependencias externas cuando pruebo los privados.
¿Estoy loco?
unit-testing
mocking
Fran Sevillano
fuente
fuente
Respuestas:
Tiene razón en parte: no debe probar directamente métodos privados. Los métodos privados en una clase deben ser invocados por uno o más de los métodos públicos (quizás indirectamente; un método privado llamado por un método público puede invocar otros métodos privados). Por lo tanto, cuando pruebe sus métodos públicos, también probará sus métodos privados. Si tiene métodos privados que no se han probado, sus casos de prueba son insuficientes o los métodos privados no se utilizan y se pueden eliminar.
Si está adoptando un enfoque de prueba de caja blanca, debe considerar los detalles de implementación de sus métodos privados al construir pruebas unitarias en torno a sus métodos públicos. Si está adoptando un enfoque de recuadro negro, no debería probar con los detalles de implementación, ya sea en los métodos públicos o privados, sino en el comportamiento esperado.
Personalmente, prefiero un enfoque de caja blanca para las pruebas unitarias. Puedo elaborar pruebas para poner a prueba los métodos y las clases en diferentes estados que causan un comportamiento interesante en mis métodos públicos y privados y luego afirmar que los resultados son lo que espero.
Entonces, no te burles de tus métodos privados. Úselos para comprender lo que necesita probar para proporcionar una buena cobertura de la funcionalidad que proporciona. Esto es especialmente cierto en el nivel de prueba de la unidad.
fuente
Creo que esta es una idea muy pobre.
El problema con la creación de pruebas unitarias de miembros privados es que encaja mal con el ciclo de vida del producto.
La razón por la que HAS ELEGIDO hacer que esos métodos sean privados es que no son fundamentales para lo que tus clases intentan hacer, solo ayudantes en cómo implementas actualmente esa funcionalidad. A medida que refactoriza, es probable que esos detalles privados sean candidatos para cambiar y causarán fricción con la refactorización.
Además, una diferencia clave entre los miembros públicos y privados es que debe pensar cuidadosamente su API pública, documentarla bien y verificarla bien (afirmaciones, etc.). Pero con una API privada, no tendría sentido pensar con tanto cuidado (un esfuerzo desperdiciado ya que su uso está muy localizado). Poner métodos privados en pruebas unitarias equivale a crear dependencias externas de esos métodos. Lo que significa que la API debe ser estable y bien documentada (ya que alguien tiene que descubrir por qué esas pruebas unitarias fallaron si / cuando lo hacen).
Te sugiero:
Apreciamos su inclinación a probar esta funcionalidad y es difícil hacerlo probar a través de su API pública actual. Pero personalmente valoro más la modularidad que la cobertura de prueba.
fuente
UnitTests prueba el comportamiento público observable , no el código, donde "público" significa: valores de retorno y comunicación con dependencias.
Una "unidad" es cualquier código que resuelve el mismo problema (o más precisamente: tiene la misma razón para cambiar). Ese podría ser un método único o un montón de clases.
La razón principal por la que no desea probar
private methods
es: son detalles de implementación y es posible que desee cambiarlos durante la refactorización (mejore su código aplicando principios OO sin cambiar la funcionalidad). Esto es exactamente cuando no desea que cambien sus pruebas de unidad para que puedan garantizar que el comportamiento de su CuT no cambió durante la refactorización.Por lo general, experimento lo contrario: cuanto más pequeñas son las clases (menos responsabilidad tienen) menos dependencias tienen y más fáciles son las pruebas unitarias, tanto para escribir como para leer.
Idealmente, aplica el mismo nivel de patrón de abstracción a sus clases. Esto significa que sus clases proporcionan alguna lógica de negocios (preferiblemente como "funciones puras" que trabajan en sus parámetros solo sin mantener un estado propio) (x) o métodos de llamada en otros objetos, no ambos al mismo tiempo.
De esta forma, las pruebas unitarias del comportamiento comercial son pan comido y los objetos de "delegación" generalmente son demasiado simples para fallar (sin ramificación, sin cambio de estado), por lo que no se necesitan pruebas unitarias y sus pruebas pueden dejarse a pruebas de integración o módulo
fuente
Las pruebas unitarias tienen cierto valor cuando usted es el único programador que trabaja en el código, especialmente si la aplicación es muy grande o muy compleja. Cuando las pruebas unitarias se vuelven esenciales es cuando tienes un mayor número de programadores trabajando en la misma base de código. El concepto de pruebas unitarias se introdujo para abordar algunas de las dificultades de trabajar en estos equipos más grandes.
La razón por la que las pruebas unitarias ayudan a los equipos más grandes se trata de contratos. Si mi código está haciendo llamadas al código escrito por otra persona, estoy haciendo suposiciones sobre lo que hará el código de la otra persona en diversas situaciones. Siempre que esos supuestos sigan siendo ciertos, mi código seguirá funcionando, pero ¿cómo sé qué supuestos son válidos y cómo sé cuándo han cambiado esos supuestos?
Aquí es donde entran las pruebas unitarias. El autor de una clase crea pruebas unitarias para documentar el comportamiento esperado de su clase. La prueba unitaria define todas las formas válidas de usar la clase, y ejecutar la prueba unitaria valida que estos casos de uso funcionen como se esperaba. Otro programador que quiera hacer uso de su clase puede leer sus pruebas unitarias para comprender el comportamiento que pueden esperar para su clase, y usar esto como base para sus suposiciones sobre cómo funciona su clase.
De esta manera, las firmas de método público de la clase y las pruebas unitarias juntas forman un contrato entre el autor de la clase y los otros programadores que hacen uso de esta clase en su código.
En este escenario, ¿qué sucede si incluye pruebas de métodos privados? Claramente no tiene sentido.
Si usted es el único programador que trabaja en su código y desea usar pruebas unitarias como una forma de depurar su código, entonces no veo ningún daño en eso, es solo una herramienta, y puede usarlo de cualquier manera que funcione usted, pero no fue la razón por la cual se introdujeron las pruebas unitarias, y no proporciona los principales beneficios de las pruebas unitarias.
fuente
Antes de responder a esa pregunta, debe decidir qué es lo que realmente quiere lograr.
Tú escribes el código. Espera que cumpla con su contrato (en otras palabras, hace lo que se supone que debe hacer. Escribir lo que se supone que debe hacer es un gran paso adelante para algunas personas).
Para estar razonablemente convencido de que el código hace lo que se supone que debe hacer, puede mirarlo lo suficiente o escribir un código de prueba que pruebe suficientes casos para convencerlo de "si el código pasa todas estas pruebas, entonces es correcto".
A menudo solo le interesa la interfaz definida públicamente de algún código. Si uso la biblioteca, no me importa cómo lo hizo funcionar correctamente, sólo que hace el trabajo correctamente. Verifico que su biblioteca es correcta realizando pruebas unitarias.
Pero estás creando la biblioteca. Hacer que funcione correctamente puede ser difícil de lograr. Digamos que solo me importa que la biblioteca haga la operación X correctamente, así que tengo una prueba unitaria para X. Usted, el desarrollador responsable de crear la biblioteca, implementa X combinando los pasos A, B y C, que son totalmente no triviales. Para que su biblioteca funcione, agregue pruebas para verificar que A, B y C funcionen correctamente. Quieres estas pruebas. Decir "no deberías tener pruebas unitarias para métodos privados" no tiene sentido. Usted desea que las pruebas para estos métodos privados. Tal vez alguien le diga que la unidad que prueba métodos privados está mal. Pero eso solo significa que no puede llamarlos "pruebas unitarias" sino "pruebas privadas" o como quiera llamarlas.
El lenguaje Swift resuelve el problema de que no desea exponer A, B, C como métodos públicos simplemente porque desea probarlo dando a las funciones un atributo "comprobable". El compilador permite que se invoquen métodos privados comprobables desde pruebas unitarias, pero no desde código que no sea de prueba.
fuente
Sí, estás loco ... ¡COMO UN ZORRO!
Hay un par de formas de probar métodos privados, algunos de los cuales dependen del idioma.
En general, si desea probar métodos privados, probablemente quiera moverlos a métodos públicos en una dependencia y probar / inyectar eso.
fuente
Mantente pragmático. Probar casos especiales en métodos privados mediante la configuración del estado de la instancia y los parámetros de un método público para que esos casos ocurran allí, a menudo es demasiado complicado.
Agrego un descriptor de
internal
acceso adicional (junto con el indicadorInternalsVisibleTo
del ensamblaje de prueba), claramente nombradoDoSomethingForTesting(parameters)
, para probar esos métodos "privados".Por supuesto, la implementación puede cambiar en algún momento, y esas pruebas, incluidos los accesores de prueba, se vuelven obsoletas. Eso sigue siendo mejor que los casos no probados o las pruebas ilegibles.
fuente