Supongamos que tenemos una gran aplicación de nivel empresarial sin pruebas unitarias / funcionales. No hubo un proceso de desarrollo basado en pruebas durante el desarrollo debido a plazos muy ajustados (sé que nunca deberíamos prometer plazos estrictos cuando no estamos seguros, ¡pero lo hecho, hecho está!)
Ahora que todos los plazos pasaron y las cosas están tranquilas, todos acordaron transformarnos en un equipo productivo basado en TDD / BDD ... ¡Yay!
Ahora la pregunta es sobre el código que ya tenemos: (1) ¿Está bien o es una buena idea detener la mayor parte del desarrollo y comenzar a escribir todos los casos de prueba posibles desde el principio, a pesar de que todo funciona completamente BIEN (todavía) ? O (2) es mejor esperar a que ocurra algo malo y luego, durante la reparación, escribir nuevas pruebas unitarias, o (3) incluso olvidarse de los códigos anteriores y simplemente escribir pruebas unitarias solo para los nuevos códigos y posponer todo al siguiente refactor principal.
Hay algunos artículos buenos y relacionados como este . Todavía no estoy seguro de si vale la pena invertir en esto teniendo en cuenta que tenemos un tiempo muy limitado y que muchos otros proyectos / trabajos nos están esperando.
Nota : Esta pregunta explica / imagina una situación totalmente incómoda en un equipo de desarrollo. No se trata de mí ni de ninguno de mis colegas; Es solo una situación imaginaria. ¡Puede pensar que esto nunca debería suceder o que el gerente de desarrollo es responsable de tal desorden! Pero de todos modos, lo hecho, hecho está. Si es posible, por favor no haga un voto negativo solo porque cree que esto nunca debería suceder.
fuente
int
valor y devuelva algo específico, no es posible escribir una prueba unitaria para cadaint
valor posible , pero probablemente tenga sentido probar un puñado de valores útiles que podrían triplicar código, como números negativos (incluidosminint
), ceromaxint
, etc. para asegurarse de que algunos casos límite estén cubiertos.Respuestas:
Esta afirmación es muy preocupante. No porque signifique que se desarrolló sin TDD o porque no está probando todo. Esto es preocupante, porque muestra que piensas que TDD te retrasará y te hará perder una fecha límite.
Mientras lo vea de esta manera, no estará listo para TDD. TDD no es algo en lo que pueda relajarse gradualmente. O sabes cómo hacerlo o no. Si intentas hacerlo a la mitad, lo lograrás y te verás mal.
TDD es algo que primero debes practicar en casa. Aprende a hacerlo, porque te ayuda a codificar ahora . No porque alguien te haya dicho que lo hagas. No porque ayudará cuando hagas cambios más tarde. Cuando se convierte en algo que haces porque tienes prisa, entonces estás listo para hacerlo profesionalmente.
TDD es algo que puedes hacer en cualquier tienda. Ni siquiera tiene que entregar su código de prueba. Puede guardarlo para usted si los demás desdeñan las pruebas. Cuando lo haces bien, las pruebas aceleran tu desarrollo incluso si nadie más las ejecuta.
Por otro lado, si otros aman y ejecutan sus pruebas, debe tener en cuenta que incluso en una tienda TDD no es su trabajo verificar las pruebas. Es crear un código de producción comprobado que funcione. Si resulta ser comprobable, ordenado.
Si cree que la gerencia tiene que creer en TDD o que sus compañeros codificadores deben respaldar sus pruebas, entonces está ignorando lo mejor que TDD hace por usted. Rápidamente le muestra la diferencia entre lo que cree que hace su código y lo que realmente hace.
Si no puede ver cómo eso, por sí solo, puede ayudarlo a cumplir con una fecha límite más rápido, entonces no está listo para TDD en el trabajo. Necesitas practicar en casa.
Dicho esto, es bueno cuando el equipo puede usar sus pruebas para ayudarlos a leer su código de producción y cuando la gerencia comprará nuevas herramientas TDD.
Independientemente de lo que esté haciendo el equipo, no siempre es una buena idea escribir todos los casos de prueba posibles. Escribe los casos de prueba más útiles. La cobertura del 100% del código tiene un costo. No ignore la ley de rendimientos decrecientes solo porque hacer un juicio es difícil.
Ahorre su energía de prueba para la interesante lógica de negocios. Lo que toma decisiones y hace cumplir la política. Prueba el diablo de eso. El código de pegamento estructural obvio, fácil de leer y aburrido que simplemente conecta cosas juntas no necesita pruebas tan mal.
No. Este es el pensamiento de "hagamos una reescritura completa". Esto destruye el conocimiento difícilmente ganado. No le pida a la gerencia tiempo para escribir exámenes. Solo escribe pruebas. Una vez que sepa lo que está haciendo, las pruebas no lo retrasarán.
Contestaré 2 y 3 de la misma manera. Cuando cambia el código, por cualquier motivo, es realmente bueno si puede pasar una prueba. Si el código es heredado, actualmente no es bienvenido una prueba. Lo que significa que es difícil probarlo antes de cambiarlo. Bueno, como lo estás cambiando de todos modos, puedes cambiarlo en algo comprobable y probarlo.
Esa es la opción nuclear. Es arriesgado. Estás haciendo cambios sin pruebas. Hay algunos trucos creativos para poner a prueba el código heredado antes de cambiarlo. Busca lo que se llama costuras que le permiten cambiar el comportamiento de su código sin cambiar el código. Cambia los archivos de configuración, crea archivos, lo que sea necesario.
Michael Feathers nos dio un libro sobre esto: Trabajando efectivamente con código heredado . Léelo y verás que no tienes que quemar todo lo viejo para hacer algo nuevo.
fuente
Dado el código heredado 1 , escriba pruebas unitarias en estas situaciones:
Por útiles que sean las pruebas unitarias, la creación de un conjunto completo de pruebas unitarias para una base de código 1 existente probablemente no sea una idea realista. Los poderes existentes te han empujado a cumplir en un plazo ajustado. No le dieron tiempo para crear pruebas unitarias adecuadas mientras desarrollaba. ¿Crees que te darán el tiempo adecuado para crear pruebas para el "programa que funciona"?
1 El código heredado es el código sin pruebas unitarias. Esta es la definición TDD de código heredado. Se aplica incluso si el código heredado se entrega recientemente [incluso si la tinta aún no se ha secado].
fuente
En mi experiencia, las pruebas no necesitan cobertura total para ser útiles. En cambio, comienza a cosechar diferentes tipos de beneficios a medida que aumenta la cobertura:
La verdad es que si no comienzas con BDD nunca llegarás allí, porque el trabajo requerido para probar después de la codificación es excesivo. El problema no es escribir las pruebas, sino más bien tener en cuenta los requisitos reales (en lugar de los detalles de implementación incidentales) y poder diseñar el software de una manera que sea funcional y fácil de probar. Cuando escribe las pruebas primero o junto con el código, esto es prácticamente gratis.
Dado que las nuevas funciones requieren pruebas, pero las pruebas requieren cambios de diseño, pero la refactorización también requiere pruebas, tiene un pequeño problema con el huevo y la gallina. A medida que su software se acerca a una cobertura decente, tendrá que realizar una refactorización cuidadosa en aquellas partes del código donde ocurren nuevas características, solo para que las nuevas características sean verificables. Esto te retrasará mucho, inicialmente. Pero al refactorizar y probar solo aquellas partes donde se necesita un nuevo desarrollo, las pruebas también se enfocan en el área donde más se necesitan. El código estable puede continuar sin pruebas: si tuviera errores, tendría que cambiarlo de todos modos.
Mientras intenta adaptarse a TDD, una mejor métrica que la cobertura total del proyecto sería la cobertura de prueba en las partes que se están cambiando. Esta cobertura debe ser muy alta desde el principio, aunque no es factible probar todas las partes del código que se ven afectadas por una refactorización. Además, obtendrá la mayoría de los beneficios de una alta cobertura de prueba dentro de los componentes probados. Eso no es perfecto, pero sigue siendo bastante bueno.
Tenga en cuenta que si bien las pruebas unitarias parecen ser comunes, comenzar con las piezas más pequeñas no es una estrategia adecuada para obtener un software heredado bajo prueba. Querrá comenzar con pruebas de integración que ejerciten una gran parte del software a la vez.
Por ejemplo, he encontrado útil extraer casos de prueba de integración de archivos de registro del mundo real. Por supuesto, ejecutar tales pruebas puede llevar mucho tiempo, por lo que es posible que desee configurar un servidor automatizado que ejecute las pruebas regularmente (por ejemplo, un servidor Jenkins activado por commits). El costo de configurar y mantener un servidor de este tipo es muy pequeño en comparación con no ejecutar pruebas regularmente, siempre que las fallas de las pruebas se solucionen rápidamente.
fuente
No escriba pruebas para el código existente. Que no vale la pena.
Lo que hiciste ya se probó de una manera completamente informal: lo probaste a mano constantemente, las personas hicieron algunas pruebas no automáticas, ahora se está usando. Eso significa que no encontrarás muchos errores .
Lo que queda son los errores en los que no pensaste. Pero esos son exactamente aquellos para los que no pensará escribir pruebas unitarias, por lo que probablemente aún no los encuentre.
Además, una razón para TDD es hacerle pensar cuáles son los requisitos exactos de un bit de código antes de escribirlo. De cualquier manera diferente, ya lo hiciste.
Mientras tanto, todavía es tanto trabajo escribir estas pruebas como lo habría sido escribirlas de antemano. Costará mucho tiempo, por poco beneficio.
Y es extremadamente aburrido escribir muchas pruebas sin codificación en el medio y sin encontrar apenas errores. Si comienzas a hacer esto, las personas nuevas en TDD lo odiarán .
En resumen, los desarrolladores lo odiarán y los gerentes lo verán como costoso, mientras que no se encuentran muchos errores. Nunca llegarás a la parte TDD real.
Úselo en las cosas que desea cambiar, como parte normal del proceso.
fuente
Una prueba es un medio para comunicar comprensión.
Por lo tanto, solo escriba pruebas de lo que entiende que debe ser cierto.
Solo puedes entender lo que debería ser cierto cuando trabajas con él.
Por lo tanto, solo escriba pruebas para el código con el que está trabajando.
Cuando trabajes con el código aprenderás.
Por lo tanto, escribe y reescribe pruebas para capturar lo que has aprendido.
Enjuague y repita.
Ejecute una herramienta de cobertura de código con sus pruebas y solo acepte confirmaciones en la línea principal que no reduzcan la cobertura. Eventualmente alcanzará un alto nivel de cobertura.
Si hace tiempo que no trabaja con el código, debe tomar una decisión comercial. Ahora es tan posible que nadie en su equipo sepa cómo trabajar con él. Probablemente tiene bibliotecas / compiladores / documentación desactualizados, lo cual es una responsabilidad enorme en casi todos los sentidos.
Dos opciones:
fuente
Uno de los principales propósitos de las pruebas es garantizar que un cambio no rompa nada. Este es un proceso de tres pasos:
Esto significa que necesita tener pruebas de funcionamiento antes de cambiar algo realmente. Si elige la segunda ruta, eso significa que tendrá que obligar a sus desarrolladores a escribir pruebas incluso antes de que toquen el código. Y sospecho fuertemente que cuando ya se enfrentan a un cambio en el mundo real, los desarrolladores no van a dar a las pruebas unitarias la atención que merecen.
Por lo tanto, sugiero dividir las tareas de redacción de pruebas y cambios para evitar que los desarrolladores sacrifiquen la calidad de uno por el otro.
Solo para señalar esto específicamente, es un error común pensar que solo necesita pruebas cuando el código no funciona. También necesita pruebas cuando el código funciona, por ejemplo, para demostrarle a alguien que [el nuevo error] no se debe a su parte porque las pruebas aún se están aprobando.
Confirmar que todo sigue funcionando como lo hizo antes es un beneficio importante de las pruebas que está omitiendo cuando implica que no necesita pruebas cuando el código está funcionando.
Idealmente, todo el código fuente existente ahora debería obtener pruebas unitarias. Sin embargo, existe un argumento razonable de que el tiempo y el esfuerzo (y el costo) necesarios para hacerlo simplemente no son relevantes para ciertos proyectos.
Por ejemplo, las aplicaciones que ya no se están desarrollando y ya no se espera que se cambien (por ejemplo, el cliente ya no lo usa, o el cliente ya no es un cliente), puede argumentar que ya no es relevante probar este código .
Sin embargo, no es tan claro donde dibujas la línea. Esto es algo que una empresa debe considerar en un análisis de costo beneficio. Escribir pruebas cuesta tiempo y esfuerzo, pero ¿esperan algún desarrollo futuro en esa aplicación? ¿Las ganancias de tener pruebas unitarias superan el costo de escribirlas?
Esta no es una decisión que usted (como desarrollador) pueda tomar. En el mejor de los casos, puede ofrecer una estimación del tiempo necesario para implementar las pruebas en un proyecto determinado, y depende de la gerencia decidir si existe una expectativa suficiente de la necesidad de mantener / desarrollar el proyecto.
Si el siguiente refactor principal es un hecho, entonces sí necesita escribir las pruebas.
Pero no lo posponga hasta que enfrente cambios importantes. Mi punto inicial (no combinar la redacción de pruebas y actualizar el código) sigue en pie, pero quiero agregar un segundo punto aquí: sus desarrolladores actualmente conocen mejor el proyecto que en seis meses si pasan ese tiempo trabajando en otros proyectos Aproveche los períodos de tiempo en los que los desarrolladores ya se han calentado y no necesitan descubrir cómo volverán a funcionar las cosas en el futuro.
fuente
Mis dos centavos:
Espere una importante actualización técnica del sistema y escriba las pruebas ... oficialmente con el apoyo de la empresa.
Alternativamente, supongamos que es una tienda SCRUM, su carga de trabajo está representada por la capacidad y puede asignar un% de eso a las pruebas unitarias, pero ...
Decir que vas a volver y escribir las pruebas es ingenuo, lo que realmente vas a hacer es escribir pruebas, refactorizar y escribir más pruebas después de que el refactor haya hecho que el código sea más verificable, por lo que es mejor comenzar con pruebas como ya sabes, y ...
Es mejor que el autor original escriba pruebas y refactorice el código que escribió anteriormente, no es ideal, pero por experiencia desea que el refactor mejore el código y no lo empeore.
fuente