TDD frente a pruebas unitarias [cerrado]

117

Mi empresa es bastante nueva en las pruebas unitarias de nuestro código. He estado leyendo sobre TDD y pruebas unitarias durante algún tiempo y estoy convencido de su valor. Intenté convencer a nuestro equipo de que TDD vale la pena el esfuerzo de aprender y cambiar nuestra forma de pensar sobre cómo programamos, pero es una lucha. Lo que me lleva a mi (s) pregunta (s).

Hay muchos en la comunidad TDD que son muy religiosos acerca de escribir la prueba y luego el código (y yo estoy con ellos), pero para un equipo que está luchando con TDD, ¿un compromiso aún trae beneficios adicionales?

Probablemente pueda lograr que el equipo escriba pruebas unitarias una vez que se escriba el código (quizás como un requisito para verificar el código) y mi suposición es que todavía hay valor en escribir esas pruebas unitarias.

¿Cuál es la mejor manera de traer un equipo con dificultades a TDD? Y si eso falla, ¿vale la pena escribir pruebas unitarias incluso si es después de escribir el código?

EDITAR

Lo que he sacado de esto es que es importante para nosotros comenzar las pruebas unitarias, en algún lugar del proceso de codificación. Para aquellos en el equipo que adopten el concepto, comiencen a moverse más hacia TDD y las pruebas primero. Gracias por el aporte de todos.

SEGUIMIENTO

Recientemente comenzamos un nuevo proyecto pequeño y una pequeña parte del equipo usó TDD, el resto escribió pruebas unitarias después del código. Después de concluir la parte de codificación del proyecto, los que escribieron pruebas unitarias después del código se sorprendieron al ver que los codificadores TDD ya estaban hechos y con un código más sólido. Fue una buena forma de ganarse a los escépticos. Todavía tenemos muchos dolores de crecimiento por delante, pero la batalla de voluntades parece haber terminado. ¡Gracias por todos los que ofrecieron consejos!

Walter
fuente
1
Puede encontrar este hilo útil: stackoverflow.com/questions/917334/should-i-use-tdd
Randolpho
29
+1 para el SEGUIMIENTO. Esa es una gran historia.
Carl Manaster

Respuestas:

76

Si el equipo tiene dificultades para implementar TDD, pero no estaban creando ninguna prueba unitaria antes ... entonces comience creando pruebas unitarias después de que se escriba su código. ¡Incluso las pruebas unitarias escritas después del código son mejores que ninguna prueba unitaria!

Una vez que dominen las pruebas unitarias (y todo lo que viene con ellas), puede trabajar para que creen primero las pruebas ... y luego codifiquen.

Justin Niessner
fuente
3
Eso es correcto, el equipo no estaba creando ninguna prueba unitaria antes. Esto se siente como un buen trampolín hacia TDD completo.
Walter
No puedo estar más de acuerdo con esto. De hecho, creo que escribí algo similar para una pregunta similar hace unos meses. ¿Dónde está ... Aah! stackoverflow.com/questions/917334/should-i-use-tdd/…
Randolpho
27

Todavía vale la pena escribir las pruebas unitarias después de escribir el código. Es solo que a veces es más difícil porque su código no fue diseñado para ser comprobable y es posible que lo haya complicado en exceso.

Creo que una buena forma pragmática de incorporar un equipo a TDD es proporcionar el método alternativo de "prueba durante el desarrollo" en el período de transición, o posiblemente a largo plazo. Se les debe animar a que utilicen las secciones de código TDD que les parezcan naturales. Sin embargo, en las secciones de código que parecen difíciles de abordar como prueba primero o cuando se utilizan objetos predeterminados por un proceso de A&D no ágil, los desarrolladores pueden tener la opción de escribir una pequeña sección del código y luego escribir pruebas para cubrir eso. código, y repitiendo este proceso. Escribir pruebas unitarias para algún código inmediatamente después de escribir ese código es mejor que no escribir ninguna prueba unitaria.

Kaleb Brasee
fuente
16

En mi humilde opinión, es mejor tener una cobertura de prueba del 50% con "código primero, prueba después" y una biblioteca completa al 100%, que cobertura de prueba al 100% y una biblioteca completa al 50% con TDD. Después de un tiempo, es de esperar que sus compañeros desarrolladores encuentren entretenido y educativo escribir pruebas para todo el publiccódigo que escriben, por lo que TDD se abrirá paso en su rutina de desarrollo.

Asbjørn Ulsberg
fuente
3
Entiendo su deriva, pero desconfío de la "biblioteca completa al 100%" con una cobertura de prueba del 50% ... solo por mi experiencia, cada fragmento de código que no está cubierto por algunas pruebas contiene al menos un error. O para decirlo de otra manera: la gente tiende a evitar escribir pruebas para el código que realmente se beneficiaría de más pruebas :)
Aaron Digulla
2
Bueno, otra forma de decirlo es que el código con errores que se ha lanzado es mejor que el código perfecto que languidece para siempre. Obviamente hay excepciones tos NASA tos , pero en su mayor parte, obtener su código por ahí. Aún puede agregar pruebas después de su lanzamiento.
jcdyer
3
¿Qué quieres decir con "biblioteca completa al 100%"? ¿Lo consideras completo si tiene buggy? ¿No incluye probado en la definición de hecho?
Pascal Thivent
10
ser probado no es una condición suficiente para estar libre de errores
fa.
2
La cobertura de prueba medida por las herramientas de cobertura de prueba es un arma de doble filo. Si se logra invocando todos los métodos en la IUT, pero las pruebas no están realmente probando el comportamiento que probablemente se rompa, los desarrolladores y otras partes interesadas tendrán una falsa sensación de seguridad. Todo el movimiento hacia TDD dentro de su organización puede estallar en su cara cuando el comportamiento crítico no se prueba, pero tiene una cobertura de prueba del 100%. Lo más importante no es la cantidad, sino la calidad.
Doug Knesek
12

Acabo de leer esto en un calendario: "Cada regla, ejecutada al máximo, se vuelve ridícula o incluso peligrosa". Así que mi sugerencia es no ser religioso al respecto. Cada miembro de su equipo debe encontrar un equilibrio entre lo que siente "correcto" cuando se trata de realizar pruebas. De esta manera, cada miembro de su equipo será más productivo (en lugar de, digamos, pensar "¿por qué tengo que escribir esta prueba rígida?").

Entonces, algunas pruebas son mejores que ninguna, las pruebas posteriores al código son mejores que unas pocas pruebas y las pruebas antes del código son mejores que después. Pero cada paso tiene sus propios méritos y no debe desaprobar ni siquiera los pasos pequeños.

Aaron Digulla
fuente
"lo que sienten" Como desarrollador, no recuerdo haber tenido ningún deseo (correcto) de realizar pruebas unitarias automatizadas a través de mis propios sentimientos, solo manuales. No creo que esté solo sin entusiasmo por las pruebas
Gennady Vanin Геннадий Ванин
@ vgv8: Eso significa que tus pruebas no te ayudan. Puede haber muchas razones por las que esto es así; Sugiero profundizar más. Cualquier proyecto se beneficia de buenas pruebas y adolece de malas. Notarás cuando comiences a escribir buenas pruebas y a partir de ese momento, nada podrá impedirte escribir más.
Aaron Digulla
lo que me parece correcto es un nivel de testing que cubre lo que deben hacer las unidades de programación, y desde un nivel funcional: lo que los usuarios están haciendo normalmente, que incluye los malos resultados que algunos denominan "errores reportados". Si se confirma un error, ¡se escribe al menos una prueba! cuanto más grande es el proyecto y más grande el equipo, más importante es esto.
DaFi4
12

TDD se trata de diseño. Entonces, si lo usa, se asegurará de tener un diseño comprobable de su código, lo que facilitará la escritura de sus pruebas. Si escribe pruebas después de escribir el código, siguen siendo valiosas pero en mi humilde opinión, estará perdiendo el tiempo ya que probablemente no tendrá un diseño comprobable.

Una sugerencia que puedo darle para tratar de convencer a su equipo de que adopte TDD es usar algunas de las técnicas descritas en Fearless Change: Patterns for Introducing New Ideas, de Mary Lynn Manns y Linda Rising .

Diego Dias
fuente
3
+1: Desarrollo basado en pruebas significa que el diseño fue impulsado por consideraciones de prueba.
S.Lott
+1. Las pruebas unitarias posteriores, por supuesto, le ayudarán, pero perderá los beneficios de tener un "diseño comprobable" si no escribe las pruebas unitarias por adelantado.
Noufal Ibrahim
9

Si son nuevos en las pruebas que en la OMI, comience probando el código que ya ha sido escrito y gradualmente gradualmente para escribir pruebas primero. Como alguien que intenta aprender TDD y es nuevo en las pruebas unitarias, me ha resultado un poco difícil hacer un 180 completo y cambiar mi forma de pensar para escribir pruebas antes del código, por lo que el enfoque que estoy adoptando es una especie de mezcla 50-50 ; cuando sepa exactamente cómo se verá el código, escribiré el código y luego escribiré una prueba para verificarlo. Para situaciones en las que no estoy del todo seguro, comenzaré con una prueba y trabajaré hacia atrás.

También recuerde que no hay nada de malo en escribir pruebas para verificar el código, en lugar de escribir código para satisfacer las pruebas. Si su equipo no quiere seguir la ruta TDD, no los fuerce.

Wayne Molina
fuente
6

Probablemente pueda lograr que el equipo escriba pruebas unitarias una vez que se escriba el código (quizás como un requisito para verificar el código) y mi suposición es que todavía hay valor en escribir esas pruebas unitarias.

No hay absolutamente ninguna duda sobre el hecho de que hay valor en el código probado por unidad (independientemente de cuándo se escribieron las pruebas) e incluyo "el código es probado por unidad" en la "Definición de Hecho". Las personas pueden usar TDD o no, siempre que realicen la prueba.

Con respecto al control de versiones, me gusta usar " ramas de desarrollo " con una política de unidad probada (es decir, el código se compila y construye, todas las pruebas de unidad pasan). Cuando las características están listas, se publican desde las ramas de desarrollo hasta el tronco. En otras palabras, la rama del tronco es la " rama Listo " (¡No hay basura en el tronco!) Y tiene un política de envío (se puede liberar en cualquier momento) que es más estricta e incluye más cosas que "unidad probada".

Pascal Thivent
fuente
4

Esto es algo con lo que su equipo tendrá que tener sus propios éxitos antes de comenzar a creer en ello. Voy a despotricar sobre mi epifanía de nUnit para cualquiera que se preocupe:

Hace unos 5 años descubrí nUnit cuando trabajaba en un proyecto. Casi habíamos completado la V1.0 y creé algunas pruebas solo para probar esta nueva herramienta. Tuvimos muchos errores (¡obviamente!) Porque éramos un equipo nuevo, con una fecha límite ajustada, expectativas altas (¿te suena familiar?), Etc. De todos modos, entramos en 1.0 y comenzamos en 1.1. Reorganizamos un poco el equipo y me asignaron 2 desarrolladores. Hice una demostración de 1 hora para ellos y les dije que todo lo que escribimos tenía que tener un caso de prueba. Corrimos constantemente "detrás" del resto del equipo durante el ciclo de desarrollo 1.1 porque estábamos escribiendo más código, las pruebas unitarias. Terminamos trabajando más, pero aquí está la recompensa: cuando finalmente comenzamos las pruebas, teníamos exactamente 0 errores en nuestro código. Ayudamos a todos los demás a depurar y reparar sus errores. En la autopsia, cuando aparecieron los recuentos de errores,

No soy lo suficientemente tonto como para pensar que puede probar su camino hacia el éxito, pero soy un verdadero creyente cuando se trata de pruebas unitarias. El proyecto adoptó nUnit y pronto se extendió a la empresa para todos los proyectos .Net como resultado de 1 éxito. El período de tiempo total para nuestro lanzamiento V1.1 fue de 9 semanas de desarrollo, por lo que definitivamente NO fue un éxito de la noche a la mañana. Pero a largo plazo, resultó ser un éxito para nuestro proyecto y la empresa para la que creamos soluciones.

Sin reembolsos Sin devoluciones
fuente
"El proyecto adoptó nUnit y pronto se extendió a la empresa para todos los proyectos .Net" ¿Y qué hacer si un producto / proyecto tiene código C #, Java, C ++, SQL Server?
Gennady Vanin Геннадий Ванин
No sé ... ¿Encontraste una manera de probar todos los componentes antes de implementarlos en producción? Las pruebas unitarias son solo una faceta de un plan de pruebas integral antes de que entre en funcionamiento. Puedes hacer agujeros en cualquier escenario.
No hay reembolsos No hay devoluciones
4

No hay duda de que las pruebas (primero, mientras o incluso después) le ayudarán a ahorrar y mejorarán su productividad y confianza. ¡Recomiendo adoptarlo!

Estaba en una situación similar, porque era un desarrollador "novato", a menudo me sentía frustrado cuando trabajaba en un proyecto de equipo por el hecho de que una contribución había roto la construcción. No sabía si yo tenía la culpa o incluso, en algunos casos, a quién culpar. Pero estaba más preocupado de estar haciendo lo mismo con mis compañeros desarrolladores. Este descubrimiento motivó entonces a adoptar algunas estrategias TDD. Nuestro equipo comenzó con juegos tontos y reglas, como si no pudieras ir a casa hasta que todas tus pruebas pasen, o si envías algo sin una prueba, entonces tienes que comprarles a todos "cerveza / almuerzo / etc." y eso hizo que TDD fuera más divertido.

Dai Bok
fuente
3

Uno de los aspectos más útiles de las pruebas unitarias es garantizar la corrección continua del código que ya funciona. Cuando pueda refactorizar a voluntad, deje que un IDE le recuerde los errores de tiempo de compilación y luego haga clic en un botón para permitir que sus pruebas detecten cualquier error de tiempo de ejecución potencial, a veces llegando a bloques de código previamente triviales, entonces creo que encontrará a su equipo empezando a apreciar TDD. Entonces, comenzar probando el código existente es definitivamente útil.

Además, para ser franco, he aprendido más sobre cómo escribir código comprobable al intentar probar el código escrito que al comenzar con TDD. Puede ser demasiado abstracto al principio si está tratando de pensar en contratos que logren el objetivo final y permitan las pruebas. Pero cuando mira el código y puede decir "Este singleton aquí arruina completamente la inyección de dependencia y hace que probar esto sea imposible", comienza a desarrollar una apreciación de qué patrones facilitan la vida de las pruebas.

David Berger
fuente
3

Bueno, si no escribe las pruebas primero, no es "basado en pruebas", es solo una prueba. Tiene beneficios en sí mismo y si ya tiene una base de código, agregar pruebas es ciertamente útil, incluso si no es TDD, sino simplemente pruebas.

Escribir pruebas primero se trata de centrarse en lo que debe hacer el código antes de escribirlo. Sí, también te hacen una prueba y es bueno, pero algunos pueden argumentar que ni siquiera es el punto más importante.

Lo que haría es entrenar al equipo en proyectos de juguetes como estos (ver Coding Dojo, Katas) usando TDD (si puede conseguir programadores TDD experimentados para participar en tal taller, sería aún mejor). Cuando vean los beneficios, usarán TDD para el proyecto real. Pero mientras tanto no los fuerce, si no ven el beneficio no lo harán bien.

kriss
fuente
3

Si tiene sesiones de diseño antes de escribir código o tiene que producir un documento de diseño, puede agregar Pruebas unitarias como resultado tangible de una sesión.

Esto podría servir como una especificación sobre cómo debería funcionar su código. Fomente el emparejamiento en la sesión de diseño para que la gente hable sobre cómo debería funcionar algo y qué debería hacer en escenarios determinados. ¿Cuáles son los casos extremos, con casos de prueba explícitos para ellos para que todos sepan lo que va a hacer si se les da un argumento nulo, por ejemplo?

Un aparte, pero BDD también puede ser de interés.

contramaestre
fuente
No estaba al tanto de BDD. Tendré que leer más sobre eso.
Walter
3

Puede encontrar algo de tracción al mostrar uno o dos ejemplos en los que TDD da como resultado que se escriba menos código, ya que solo escribe el código necesario para aprobar la prueba, la tentación de chapa de oro o participar en YAGNI es más fácil de resistir. El código que no escribe no necesita ser mantenido, refactorizado, etc., por lo que es un "ahorro real" que puede ayudar a vender el concepto de TDD.

Si puede demostrar claramente el valor en términos de tiempo, costo, código y errores guardados, es posible que descubra que es más fácil de vender.

Michael Nash
fuente
2

Comenzar a construir clases de prueba JUnit es la forma de comenzar, para el código existente es la única forma de comenzar. En mi experiencia, es muy útil crear clases de prueba para el código existente. Si la gerencia piensa que esto invertirá demasiado tiempo, puede proponer escribir clases de prueba solo cuando se encuentre que la clase correspondiente contiene un error o necesita una limpieza.

Para el proceso de mantenimiento, el enfoque para que el equipo pase de la línea sería escribir pruebas JUnit para reproducir errores antes de corregirlos, es decir

  • se informa error
  • cree la clase de prueba JUnit si es necesario
  • agregue una prueba que reproduzca el error
  • arregla tu código
  • ejecutar la prueba para mostrar que el código actual no reproduce el error

Puede explicar que "documentar" los errores de esta manera evitará que esos errores vuelvan a aparecer más tarde. Ese es un beneficio que el equipo puede experimentar de inmediato.

rsp
fuente
2

He hecho esto en muchas organizaciones y he encontrado que la mejor manera de iniciar y seguir TDD es configurar la programación de pares. Si tiene a alguien más con quien pueda contar que conozca TDD, entonces los dos pueden separarse y emparejarse con otros desarrolladores para hacer una programación emparejada usando TDD. Si no, capacitaría a alguien que lo ayude a hacer esto antes de presentárselo al resto del equipo.

Uno de los principales obstáculos con las pruebas unitarias y especialmente con TDD es que los desarrolladores no saben cómo hacerlo, por lo que no pueden ver cómo puede valer la pena su tiempo. Además, cuando comienza, es mucho más lento y no parece proporcionar beneficios. Realmente solo le brinda beneficios cuando se le da bien. Al configurar sesiones de programación emparejadas, puede hacer que los desarrolladores puedan aprenderlo rápidamente y mejorarlo más rápido. Además, podrán ver beneficios inmediatos a medida que lo trabajen juntos.

Este enfoque me ha funcionado muchas veces en el pasado.

John Sonmez
fuente
2

Una forma poderosa de descubrir los beneficios de TDD es hacer una reescritura significativa de algunas funciones existentes, quizás por razones de rendimiento. Al crear un conjunto de pruebas que hacen un buen trabajo cubriendo toda la funcionalidad del código existente, esto le da la confianza para refactorizar al contenido de su corazón con plena confianza de que sus cambios son seguros.

Tenga en cuenta que, en este caso, estoy hablando de probar el diseño o el contrato: pruebas unitarias en las que los detalles de implementación de la prueba no serán adecuados aquí. Pero, de nuevo, TDD no puede probar la implementación por definición, ya que se supone que deben estar escritos antes de la implementación.

Chris Welsh
fuente
1

TDD es una herramienta que los desarrolladores pueden utilizar para producir un mejor código. Siento que el ejercicio de escribir código comprobable es tan valioso como las pruebas mismas. Aislar la IUT (implementación bajo prueba) con fines de prueba tiene el efecto secundario de desacoplar su código.

TDD no es para todos, y no hay magia que haga que un equipo elija hacerlo. El riesgo es que los redactores de pruebas unitarias que no saben qué es lo que vale la pena probar escriban muchas pruebas de bajo valor, que serán carne de cañón para los escépticos de TDD en su organización.

Normalmente hago pruebas de aceptación automatizadas no sean negociables, pero permito a los desarrolladores adoptar TDD según les convenga. Mis TDD experimentados capacitan / asesoran al resto y "prueban" la utilidad con el ejemplo durante un período de muchos meses.

Este es un cambio tanto social / cultural como técnico.

Doug Knesek
fuente