En el desarrollo de TDD, lo primero que suele hacer es crear su interfaz y luego comenzar a escribir sus pruebas unitarias en esa interfaz. A medida que avanza en el proceso TDD, terminaría creando una clase que implementa la interfaz y luego, en algún momento, su prueba unitaria pasaría.
Ahora mi pregunta es sobre los métodos privados y protegidos que podría tener que escribir en mi clase en apoyo de los métodos / propiedades expuestos por la interfaz:
¿Deberían los métodos privados de la clase tener sus propias pruebas unitarias?
¿Los métodos protegidos de la clase deberían tener sus propias pruebas unitarias?
Mis pensamientos:
Especialmente porque estoy codificando interfaces, no debería preocuparme por métodos protegidos / privados, ya que son cajas negras.
Debido a que estoy usando interfaces, estoy escribiendo pruebas unitarias para validar que el contrato definido está implementado correctamente por las diferentes clases que implementan la interfaz, por lo que nuevamente no debería preocuparme por los métodos privados / protegidos y deben ejercerse a través de pruebas unitarias que llaman al métodos / propiedades definidos por la interfaz.
Si mi cobertura de código no muestra que los métodos protegidos / privados están siendo afectados, entonces no tengo las pruebas unitarias correctas o tengo un código que no se está usando y debería eliminarse.
fuente
Respuestas:
No, no pienso en probar métodos privados o protegidos. Los métodos privados y protegidos de una clase no forman parte de la interfaz pública, por lo que no exponen el comportamiento público. Generalmente, estos métodos se crean mediante refactorizaciones que aplica después de haber hecho que su prueba se vuelva verde.
Entonces estos métodos privados se prueban implícitamente mediante las pruebas que afirman el comportamiento de su interfaz pública.
En una nota más filosófica, recuerde que está probando el comportamiento, no los métodos. Entonces, si piensa en el conjunto de cosas que la clase bajo prueba puede hacer, siempre que pueda probar y afirmar que la clase se comporta como se espera, si hay métodos privados (y protegidos) que la clase usa internamente para implementar ese comportamiento es irrelevante. Esos métodos son detalles de implementación del comportamiento público.
fuente
No estoy de acuerdo con la mayoría de los carteles.
La regla más importante es: EL CÓDIGO DE TRABAJO SUPERA LAS REGLAS TEÓRICAS sobre público / protegido / privado.
Su código debe probarse a fondo. Si puede llegar allí escribiendo pruebas para los métodos públicos, que ejerciten suficientemente los métodos protegidos / privados, eso es genial.
Si no puede, refactorice para que pueda, o doble las reglas protegidas / privadas.
Hay una gran historia sobre un psicólogo que les hizo una prueba a los niños. Le dio a cada niño dos tablas de madera con una cuerda atada a cada extremo y les pidió que cruzaran una habitación sin tocar el suelo con los pies, lo más rápido posible. Todos los niños usaban las tablas como pequeños esquís, con un pie en cada tabla, sujetándolas por las cuerdas y deslizándose por el suelo. Luego les dio la misma tarea, pero usando solo UNA tabla. Giraron / "caminaron" por el suelo, con un pie en cada extremo de la única tabla, ¡y fueron MÁS RÁPIDOS!
El hecho de que Java (o cualquier idioma) tenga una función (privada / protegida / pública) no significa necesariamente que esté escribiendo un código mejor porque lo usa.
Ahora, siempre habrá formas de optimizar / minimizar este conflicto. En la mayoría de los lenguajes, puede hacer que un método esté protegido (en lugar de público) y poner la clase de prueba en el mismo paquete (o lo que sea), y el método estará disponible para la prueba. Hay anotaciones que pueden ayudar, como se describe en otros carteles. Puedes usar la reflexión para llegar a los métodos privados (puaj).
El contexto también importa. Si está escribiendo una API para que la utilicen personas externas, lo público / privado es más importante. Si es un proyecto interno, ¿a quién le importa?
Pero al final del día, piense en cuántos errores han sido causados por la falta de pruebas. Luego compare con cuántos errores han sido causados por métodos "demasiado visibles". Esa respuesta debería impulsar tu decisión.
fuente
Tu escribiste:
Permítanme reformular esto en lenguaje BDD :
Esta es la razón por la que no prueba métodos privados, porque una prueba es un ejemplo de cómo usar la clase, y en realidad no puede usarlos. Algo que puede hacer si lo desea es delegar las responsabilidades en los métodos privados a una clase colaboradora, luego simular / eliminar ese ayudante.
Con métodos protegidos, estás diciendo que una clase que amplía tu clase debería tener un comportamiento particular y proporcionar algún valor. Luego, podría usar extensiones de su clase para demostrar ese comportamiento. Por ejemplo, si estuviera escribiendo una clase de colección ordenada, es posible que desee demostrar que dos extensiones con el mismo contenido demostraron igualdad.
¡Espero que esto ayude!
fuente
Cuando escribe las pruebas unitarias para su clase, no debe preocuparse necesariamente si la funcionalidad de la clase se implementa directamente en el método en la interfaz pública o si se implementa en una serie de métodos privados. Entonces, sí, debería probar sus métodos privados, pero no debería necesitar llamarlos directamente desde su código de prueba para hacerlo (probar directamente los métodos privados combina estrechamente su implementación con sus pruebas y hace que la refactorización sea innecesariamente difícil).
Los métodos protegidos forman un contrato diferente entre su clase y sus futuros hijos, por lo que realmente debería probarlos de manera similar a su interfaz pública para asegurarse de que el contrato esté bien definido y ejecutado.
fuente
¡No! Solo prueba interfaces.
Uno de los grandes beneficios de TDD es garantizar que la interfaz funcione sin importar cómo haya elegido implementar los métodos privados.
fuente
Completando lo que otros dijeron anteriormente, diría que los métodos protegidos son parte de una interfaz de algún tipo: simplemente resulta ser el que está expuesto a la herencia en lugar de la composición, que es en lo que todos tienden a pensar cuando se consideran interfaces.
Marcar un método como protegido en lugar de privado significa que se espera que sea utilizado por un código de terceros, por lo que es necesario definir y probar algún tipo de contrato, como sucede con las interfaces normales definidas por métodos públicos, que están abiertos tanto para herencia como para composición. .
fuente
Hay dos razones para escribir pruebas:
La toma de (1) Afirmar el comportamiento esperado:
Cuando afirma el comportamiento esperado, quiere asegurarse de que el código funcione como cree que debería. Esta es efectivamente una forma automatizada de realizar su verificación manual de rutina que cualquier desarrollador realizaría al implementar cualquier tipo de código:
Esas son preguntas que todos respondemos en nuestras cabezas y, normalmente, intentamos ejecutar el código en nuestras cabezas también, asegurarnos de que parezca que funciona. Para estos casos, a menudo es útil que la computadora los responda de manera definitiva. Entonces escribimos una prueba unitaria que afirma que sí. Esto nos da confianza en nuestro código, nos ayuda a encontrar defectos temprano e incluso puede ayudarnos a implementar el código.
Es una buena idea hacer esto donde lo crea necesario. Cualquier código que sea un poco complicado de entender o que no sea trivial. Incluso el código trivial podría beneficiarse de ello. Se trata de tu propia confianza. La frecuencia con que lo haga y hasta dónde llegar dependerá de su propia satisfacción. Deténgase cuando pueda responder con seguridad Sí a: ¿Está seguro de que esto funciona?
Para este tipo de pruebas, a usted no le importa la visibilidad, las interfaces ni nada de eso, solo le importa tener un código que funcione. Entonces, sí, probaría los métodos privados y protegidos si cree que deben probarse para responder Sí a la pregunta.
La toma de (2) Prevención de la regresión del comportamiento:
Una vez que tenga el código que funcione, debe tener un mecanismo para proteger este código de daños futuros. Si nadie volviera a tocar su fuente y su configuración nunca más, no necesitaría esto, pero en la mayoría de los casos, usted u otros estarán tocando la fuente y las configuraciones de su software. Es muy probable que esta manipulación interna rompa su código de trabajo.
Ya existen mecanismos en la mayoría de los idiomas como una forma de protegerse contra este daño. Las características de visibilidad son un mecanismo. Un método privado está aislado y oculto. La encapsulación es otro mecanismo, en el que se compartimentan las cosas, para que cambiar otros compartimentos no afecte a los demás.
El mecanismo general para esto se llama: codificación hasta el límite. Al crear límites entre partes del código, protege todo lo que se encuentra dentro de un límite de las cosas que están fuera de él. Los límites se convierten en el punto de interacción y el contrato mediante el cual las cosas interactúan.
Esto significa que los cambios en un límite, ya sea rompiendo su interfaz o rompiendo su comportamiento esperado, dañarían y posiblemente romperían otros límites que dependían de él. Por eso es una buena idea tener una prueba unitaria, que se dirija a esos límites y afirme que no cambian en semántica ni en comportamiento.
Esta es su prueba unitaria típica, de la que casi todo el mundo habla cuando menciona TDD o BDD. El punto es endurecer los límites y protegerlos del cambio. No desea probar métodos privados para esto, porque un método privado no es un límite. Los métodos protegidos son un límite restringido y yo los protegería. No están expuestos al mundo, pero aún están expuestos a otros compartimentos o "Unidades".
¿Qué hacer con esto?
Como hemos visto, hay una buena razón para realizar pruebas unitarias de métodos públicos y protegidos, para afirmar que nuestras interfaces no cambian. Y también hay una buena razón para probar métodos privados, como para afirmar que nuestra implementación funciona. Entonces, ¿deberíamos probarlos todos por unidad?
Si y no.
En primer lugar : pruebe todos los métodos que crea que necesita una prueba definitiva de que funciona en la mayoría de los casos para poder estar seguro de que su código funciona, sin importar la visibilidad. Luego, desactive esas pruebas. Han hecho su trabajo.
Finalmente : escribe pruebas para tus límites. Realice una prueba unitaria para cada punto que utilizarán otras unidades de su sistema. Asegúrese de que esta prueba afirme el contrato semántico, el nombre del método, el número de argumentos, etc. Y también asegúrese de que la prueba afirme el comportamiento disponible de la unidad. Su prueba debe demostrar cómo usar la unidad y qué puede hacer la unidad. Mantenga estas pruebas habilitadas para que se ejecuten en cada inserción de código.
NOTA: La razón por la que desactivó el primer conjunto de pruebas es para permitir que se produzca el trabajo de refactorización. Una prueba activa es un código de acoplamiento. Evita modificaciones futuras del código que está probando. Solo desea esto para sus interfaces y contratos de interacción.
fuente
No, no deberías probar métodos privados (¿cómo lo harías de todos modos sin usar algo horrible como la reflexión?). Con los métodos protegidos, es un poco menos obvio en C # que puede hacer que las cosas estén protegidas como internas y creo que está bien hacerlo para probar clases derivadas que implementan toda su funcionalidad a través de métodos de patrón de plantilla.
Pero, en general, si cree que sus métodos públicos están haciendo demasiado, entonces es hora de refactorizar sus clases en más clases atómicas y luego probar esas clases.
fuente
Yo también estoy de acuerdo con la respuesta de @ kwbeam sobre no probar métodos privados. Sin embargo, un punto importante que me gustaría resaltar: los métodos protegidos SON parte de la API exportada de una clase y, por lo tanto, DEBEN probarse.
Es posible que los métodos protegidos no sean de acceso público, pero definitivamente está proporcionando una forma para que las subclases los usen / anulen. Algo fuera de la clase puede acceder a ellos y, por lo tanto, debe asegurarse de que esos miembros protegidos se comporten de la manera esperada. Por lo tanto, no pruebe los métodos privados, pruebe los métodos públicos y protegidos.
Si cree que tiene un método privado que contiene lógica crítica, trataría de extraerlo en un objeto separado, aislarlo y proporcionar una forma de probar su comportamiento.
¡Espero eso ayude!
fuente
Si su objetivo es una alta cobertura de código (le sugiero que lo haga), debe probar todos sus métodos, independientemente de que sean privados o protegidos.
Protegido es una especie de punto de discusión diferente, pero en resumen, no debería estar allí en absoluto. O rompe la encapsulación en el código implementado, o lo obliga a heredar de esa clase, solo para probarlo unitariamente, incluso a veces no es necesario heredar.
El simple hecho de ocultar un método al cliente (convertirlo en privado) no le otorga el privilegio de no ser auditado. Por lo tanto, pueden probarse mediante métodos públicos como se mencionó anteriormente.
fuente
Estoy de acuerdo con todos los demás: la respuesta a su pregunta es "no".
De hecho, está completamente en lo cierto con su enfoque y sus pensamientos, especialmente sobre la cobertura del código.
También agregaría que la pregunta (y la respuesta 'no') también se aplica a los métodos públicos que podría introducir en las clases.
Además, para C ++ (y debería pensar solo para C ++) implemento interfaces usando solo métodos privados, para indicar que la clase solo debe usarse a través de la interfaz que implementa. Me detiene llamando por error a nuevos métodos agregados a mi implementación desde mis pruebas
fuente
Un buen diseño significa dividir la aplicación en varias unidades probables. Después de hacer esto, algunas unidades quedan expuestas a la API pública, pero es posible que otras no. Además, los puntos de interacción entre las unidades expuestas y estas unidades "internas" tampoco forman parte de la API pública.
Creo que una vez que tengamos la unidad identificable, se beneficiaría de las pruebas unitarias, independientemente de si se expone a través de API pública o no.
fuente