Trabajo en una pequeña empresa como desarrollador en solitario. Soy el único desarrollador de la compañía, de hecho. Tengo varios proyectos (relativamente) grandes que he escrito y mantengo regularmente, y ninguno de ellos tiene pruebas para respaldarlos. Cuando comienzo nuevos proyectos, a menudo me pregunto si debería intentar un enfoque TDD. Parece una buena idea, pero honestamente nunca puedo justificar el trabajo extra involucrado.
Trabajo duro para ser progresista en mi diseño. Me doy cuenta de que ciertamente algún día otro desarrollador tendrá que mantener mi código, o al menos solucionarlo. Mantengo las cosas lo más simple posible y comento y documento cosas que serían difíciles de entender. Y el hecho es que estos proyectos no son tan grandes o complicados que un desarrollador decente tendría dificultades para comprenderlos.
Muchos de los ejemplos que he visto de pruebas se reducen a minucias y cubren todas las facetas del código. Como soy el único desarrollador y estoy muy cerca del código en todo el proyecto, es mucho más eficiente seguir un patrón de prueba de escritura y luego manual. También encuentro que los requisitos y las características cambian con la frecuencia suficiente para mantener las pruebas agregaría una cantidad considerable de resistencia en un proyecto. Tiempo que de otro modo podría gastarse en resolver las necesidades del negocio.
Así que termino con la misma conclusión cada vez. El retorno de la inversión es demasiado bajo.
De vez en cuando he configurado algunas pruebas para asegurarme de haber escrito un algoritmo correctamente, como calcular el número de años que alguien ha estado en la empresa en función de su fecha de contratación. Pero desde el punto de vista de la cobertura del código, he cubierto aproximadamente el 1% de mi código.
En mi situación, ¿aún encontraría una manera de hacer que las pruebas unitarias sean una práctica regular, o estoy justificado para evitar esa sobrecarga?
ACTUALIZACIÓN: Algunas cosas sobre mi situación que omití: Mis proyectos son todas aplicaciones web. Para cubrir todo mi código, tendría que usar pruebas de interfaz de usuario automatizadas, y esa es un área donde todavía no veo un gran beneficio sobre las pruebas manuales.
fuente
Respuestas:
¿Entonces? No tienes que probar todo . Solo las cosas relevantes.
Eso es realmente falso. No es más eficiente. Realmente es solo un hábito.
Lo que hacen otros desarrolladores en solitario es escribir un boceto o esquema, escribir los casos de prueba y luego completar el esquema con el código final.
Eso es muy, muy eficiente.
Eso también es falso. Las pruebas no son el arrastre. Los requisitos de cambios son el arrastre.
Tienes que arreglar las pruebas para reflejar los requisitos. Ya sea sus minucias, o de alto nivel; escrito primero o escrito al final.
El código no está listo hasta que pasen las pruebas. Esa es la única verdad universal del software.
Puede tener una prueba de aceptación limitada "aquí está".
O puede hacerse algunas pruebas unitarias.
O puedes tener ambos.
Pero no importa lo que haga, siempre hay una prueba para demostrar que el software funciona.
Sugeriría que un poco de formalidad y un buen conjunto de herramientas de prueba unitaria hacen que esa prueba sea mucho más útil.
fuente
sqrt(-1)
debería ser un número entero, obtendría respuestas abrumadoras que se inclinarían hacia un lado. El balance está en torno a "cómo" y "qué orden". El simple hecho es que debes probar. Así que primero escribe las pruebas y asegúrate de que funcionen.Imagine que tiene un conjunto de pruebas que pueden ejecutarse en un abrir y cerrar de ojos y encender una luz verde o roja. ¡Imagínese que este conjunto de pruebas lo probó todo ! Imagine que todo lo que tenía que hacer para ejecutar el conjunto de pruebas era escribir ^ T. ¿Qué poder te daría esto?
¿Podría hacer un cambio en el código sin temor a romper algo? ¿Podría agregar una nueva función sin temor a romper una antigua? ¿Podrías limpiar el código desordenado rápidamente sin temor a hacer daño?
¡Sí, podrías hacer todas esas cosas! ¿Y qué pasaría con su código con el tiempo? Se volvería más y más limpio porque no habría riesgo de limpiarlo.
Imaginemos que tienes una pequeña hada en tu hombro. Cada vez que escribes una línea de código, el hada agrega algo al conjunto de pruebas que prueba que esa línea de código hizo lo que se pretendía hacer. Entonces, cada dos segundos, podría presionar ^ T y ver que la última línea de código que escribió funcionó.
¿Cuánta depuración crees que harías?
Si esto suena como fantasía, tienes razón. Pero la realidad no es muy diferente. Reemplaza el parpadeo con unos segundos y el hada con la disciplina TDD, y ya lo tienes.
Digamos que está volviendo a un sistema que construyó hace un año, y ha olvidado cómo crear uno de los objetos centrales. Hay pruebas que crean ese objeto de todas las formas en que se puede crear. Puedes leer esas pruebas y refrescar tu memoria. ¿Necesita llamar a una API? Hay pruebas que llaman a esa API en todos los sentidos. Estas pruebas son pequeños documentos , escritos en un idioma que usted entiende. Son completamente inequívocos. Son tan formales que se ejecutan. ¡Y no pueden salir de la sincronización con la aplicación!
¿No vale la pena la inversión? ¡Tienes que estar bromeando! ¿Cómo podría alguien NO querer ese conjunto de pruebas? Hazte un favor y deja de discutir sobre tonterías. Aprenda a hacer TDD bien y observe cuánto más rápido va y cuánto más limpio es su código.
fuente
El error que está cometiendo es que está viendo las pruebas como una inversión de tiempo sin retorno inmediato. No necesariamente funciona así.
En primer lugar, escribir pruebas realmente te enfoca en lo que esta parte de tu código debe hacer.
En segundo lugar, ejecutarlos revela errores que de otro modo aparecerían en las pruebas.
En tercer lugar, ejecutarlos a veces muestra errores que de otro modo no aparecerían en las pruebas y luego realmente te morderían en la producción.
En cuarto lugar, si encuentra un error con un sistema que se está ejecutando y crea una prueba unitaria para él, no podrá volver a introducir ese error más tarde. Eso puede ser de gran ayuda. Los errores reintroducidos son comunes y muy molestos.
En quinto lugar, si alguna vez necesita entregar el código a otra persona, un conjunto de pruebas les facilitará la vida. Además, si ha ignorado un proyecto y vuelve a él después de unos años, ya no estará tan cerca de él y también será útil para usted.
Mi experiencia ha sido consistentemente que durante el desarrollo de un proyecto, tener pruebas unitarias decentes siempre ha hecho que el proceso sea más rápido y confiable.
fuente
Los chicos de JUnit (marco de prueba de la Unidad Java) tienen la filosofía de que si es demasiado simple de probar, no lo pruebes . Recomiendo leer sus preguntas frecuentes sobre mejores prácticas , ya que es bastante pragmático.
TDD es un proceso diferente de escribir su software. La premisa básica detrás de las pruebas unitarias es que pasará menos tiempo en el depurador revisando el código, y descubrirá más rápidamente si su cambio de código rompe accidentalmente algo más en el sistema. Eso encaja con TDD. El ciclo TDD es así:
Lo que es menos obvio sobre la aplicación de TDD es que cambia la forma en que escribe su código . Al obligarse a pensar en cómo probar / validar que el código está funcionando, está escribiendo código comprobable. Y dado que estamos hablando de pruebas unitarias, eso generalmente significa que su código se vuelve más modular. Para mí, el código modular y comprobable es una gran victoria por adelantado.
Ahora, ¿necesita probar cosas como las propiedades de C #? Imagine una propiedad definida como esta:
La respuesta sería "no", no vale la pena probarlo, porque en este momento está probando la función de idioma. Solo confía en que los chicos de la plataforma C # lo hicieron bien. Además, si falla, ¿qué podrías hacer para arreglarlo?
Además, encontrará que hay ciertas partes de su código que muy bien requerirán demasiado esfuerzo para probarlas correctamente. Eso significa que no lo hagas, pero asegúrate de probar el código que usa / es usado por el problema complicado:
Lo creas o no, TDD te ayudará a alcanzar un ritmo de desarrollo sostenible. No es por magia, sino porque tienes un ciclo de retroalimentación ajustado y eres capaz de atrapar errores realmente tontos rápidamente. El costo de corregir esos errores es esencialmente constante (al menos suficiente para fines de planificación) porque los pequeños errores nunca se convierten en grandes errores. Compare eso con la naturaleza explosiva de los sprints de borrachera / depuración de código.
fuente
Debe equilibrar el costo de las pruebas con el costo de los errores.
Escribir una prueba de unidad de 10 líneas para una función que abre un archivo, donde la falla es "archivo no encontrado" no tiene sentido.
Una función que hace algo complejo a una estructura de datos compleja, entonces obviamente sí.
La parte difícil está en el medio. Pero recuerde que el valor real de las pruebas unitarias no es probar la función particular, sino probar las interacciones difíciles entre ellas. Entonces, una prueba de unidad que detecta que un cambio en un bit de código, rompe alguna función en un módulo diferente a 1000 líneas de distancia, vale su peso en café.
fuente
Las pruebas son juegos de azar.
Crear una prueba es una apuesta de que el costo de los errores en una unidad que ocurre y que no los atrapa con esa prueba (ahora y durante todas las revisiones futuras del código) es mayor que el costo de desarrollar la prueba. Esos costos de desarrollo de pruebas incluyen cosas como nómina para ingeniería de prueba adicional, tiempo de comercialización adicional, costos de oportunidad perdidos por no codificar otras cosas, etc.
Como cualquier apuesta, a veces ganas, a veces pierdes.
En algún momento, el software tardío con muchos menos errores gana sobre las cosas rápidas pero con errores que llegan primero al mercado. A veces lo contrario. Tienes que mirar las estadísticas en tu campo particular, y cuánto quiere apostar la administración.
Es posible que algunos tipos de errores no se realicen o que se eliminen de las pruebas de sanidad tempranas, de modo que estadísticamente no valga la pena el tiempo para crear pruebas específicas adicionales. Pero a veces el costo de un error es tan grande (médico, nuclear, etc.) que una empresa debe asumir una apuesta perdedora (similar a comprar un seguro). Muchas aplicaciones no tienen un costo de falla tan alto y, por lo tanto, no necesitan la mayor cobertura de seguro antieconómica. Otros lo hacen.
fuente
Mi consejo es que solo pruebe el código que desea que funcione correctamente.
No pruebe el código que desea que tenga errores y que le cause problemas en el futuro.
fuente
TDD y Unit Testing no son lo mismo.
Puede escribir código y luego agregar pruebas unitarias más tarde. Eso no es TDD, y es mucho trabajo extra.
TDD es la práctica de codificación en un bucle de luz roja. Luz verde. Refactorizar iteraciones.
Esto significa escribir pruebas para el código que aún no existe, ver fallar las pruebas, arreglar el código para que las pruebas funcionen y luego hacer que el código sea "correcto". Esto a menudo te ahorra trabajo
Una de las ventajas de TDD es que reduce la necesidad de pensar en trivia. Cosas como los errores fuera de uno desaparecen. No tiene que buscar en la documentación de la API para averiguar si la lista que devuelve comienza en 0 o 1, simplemente hágalo.
fuente
Trabajé en un sistema donde probamos casi todo. Las ejecuciones notables de las pruebas fueron el código de salida PDF y XLS.
¿Por qué? Pudimos probar las partes que recopilaron los datos y construimos el modelo que se utilizó para crear la salida. También pudimos probar las partes que descubrieron qué partes del modelo irían a los archivos PDF. No pudimos probar si el PDF se veía bien porque eso era totalmente subjetivo. No pudimos probar que todas las partes en un PDF fueran legibles para un usuario típico porque eso también era subjetivo. O si la elección entre barras y gráficos circulares era correcta para el conjunto de datos.
Si la salida va a ser subjetiva, hay pocas pruebas unitarias que puede hacer lo que vale la pena.
fuente
Para muchas cosas, una 'escritura-luego-prueba-manual' no toma más tiempo que escribir un par de pruebas. El ahorro de tiempo proviene de poder volver a ejecutar esas pruebas en cualquier momento.
Piense en ello: si tiene algún tipo de cobertura función decente con sus pruebas (que no debe confundirse con la cobertura de código), y supongamos que tiene 10 características - clic en un botón significa que tiene más o menos, 10 yous re-hacer sus pruebas ... mientras te sientas y tomas un café.
Tampoco tienes que probar las minutas. Puede escribir pruebas de integración que cubran sus características si no quiere llegar a los detalles esenciales ... En mi opinión, algunas pruebas unitarias son demasiado precisas para probar el idioma y la plataforma, y no el código.
TL; DR Realmente nunca es apropiado porque los beneficios son demasiado buenos.
fuente
Aquí hay dos respuestas muy buenas que he encontrado:
Las justificaciones para evitar la sobrecarga percibida:
¿No le gustaría dejar un gran producto a su lado como prueba de la calidad de su trabajo? Hablando en términos egoístas, ¿no es mejor para ti que lo hagas?
fuente
Los desarrolladores profesionales escriben pruebas unitarias porque, a largo plazo, ahorran tiempo. Usted probará su código tarde o temprano, y si no lo hace, sus usuarios lo harán, y si tiene que corregir los errores más tarde, serán más difíciles de corregir y tendrán más efectos negativos.
Si está escribiendo código sin pruebas y no tiene errores, entonces está bien. Sin embargo, no creo que pueda escribir un sistema no trivial con cero errores, así que supongo que lo está probando de una forma u otra.
Las pruebas unitarias también son cruciales para evitar regresiones cuando modifica o refactoriza código antiguo. No prueban que su cambio no haya roto el código anterior, pero le brindan mucha confianza (siempre que pasen, por supuesto :))
No regresaría y escribiría un lote completo de pruebas para el código que ya ha enviado, pero la próxima vez que necesite modificar una función, le sugiero que intente escribir pruebas para ese módulo o clase, obtenga su cobertura hasta un 70% + antes de aplicar cualquier cambio. A ver si te ayuda.
Si lo prueba y puede decir honestamente que no fue de ayuda, entonces es lo suficientemente justo, pero creo que hay suficiente evidencia de la industria de que ayudan a que al menos valga la pena probar el enfoque.
fuente
Parece que la mayoría de las respuestas son pro-TDD, a pesar de que la pregunta no era sobre TDD sino sobre pruebas unitarias en general.
No hay una regla completamente objetiva detrás de qué prueba unitaria o no una prueba unitaria. Pero hay un par de veces en las que parece que muchos programadores no realizan pruebas unitarias:
Dependiendo de su filosofía OOP, puede crear métodos privados para desacoplar rutinas complejas de sus métodos públicos. Los métodos públicos generalmente están destinados a ser llamados en muchos lugares diferentes y se usan con frecuencia, y los métodos privados solo se llaman realmente por uno o dos métodos públicos en una clase o módulo para algo muy específico. Por lo general, es suficiente escribir pruebas unitarias para métodos públicos, pero no los métodos privados subyacentes que hacen que algo de la magia suceda. Si algo sale mal con un método privado, las pruebas de unidad de método público deberían ser lo suficientemente buenas como para detectar estos problemas.
Muchos programadores nuevos van en contra de esto cuando están aprendiendo a probar por primera vez, y piensan que necesitan probar cada línea que se está ejecutando. Si está utilizando una biblioteca externa y su funcionalidad está bien probada y documentada por sus autores, generalmente no tiene sentido probar la funcionalidad específica en las pruebas unitarias. Por ejemplo, alguien podría escribir una prueba para asegurarse de que su modelo ActiveRecord persista el valor correcto para un atributo con una devolución de llamada "before_save" a la base de datos, a pesar de que ese comportamiento ya está probado en Rails. Los métodos a los que llama la devolución de llamada, tal vez, pero no el comportamiento de devolución de llamada en sí. Cualquier problema subyacente con las bibliotecas importadas se revelaría mejor a través de pruebas de aceptación, en lugar de pruebas unitarias.
Ambos podrían aplicarse tanto si está haciendo TDD como si no.
fuente
Ken, yo y muchos otros desarrolladores hemos llegado a la misma conclusión que tú varias veces a lo largo de nuestras carreras.
La verdad que creo que encontrará (como muchos otros) es que la inversión inicial de escribir pruebas para su aplicación puede parecer desalentadora, pero si se escribe bien y se dirige a las partes correctas de su código, realmente pueden ahorrar una tonelada de tiempo.
Mi gran problema fue con los marcos de prueba disponibles. Realmente nunca sentí que eran lo que estaba buscando, así que simplemente lancé mi propia solución muy simple. Realmente ayudó a llevarme al "lado oscuro" de las pruebas de regresión. Compartiré un pseudo fragmento básico de lo que hice aquí, y espero que pueda encontrar una solución que funcione para usted.
La única parte difícil después de eso es descubrir qué nivel de granularidad crees que es la mejor opción para cualquier proyecto que estés haciendo.
Obviamente, crear una libreta de direcciones requerirá mucho menos pruebas que un motor de búsqueda empresarial, pero los fundamentos no cambian realmente.
¡Buena suerte!
fuente