martes, agosto 17, 2010

No escribo pruebas unitarias porque... (manual de excusas)

Siendo alguien que vive los beneficios de hacer TDD, creo profundamente en el desarrollo guiado por pruebas. Esta práctica agrega un nuevo nivel de calidad y madurez al desarrollo de software, y sin embargo todavía no es la técnica más usada en los proyectos de software. Cuando hay que elegir entre características, tiempo y calidad, siempre sufre la calidad. No queremos agregar tiempo extra para hacer pruebas, y tampoco queremos comprometer las características que vamos a entregar. Si no se pusieron como objetivo hacer TDD al iniciar el proeycto, es dificil hacerlo después.

Todos escuchamos excusas para no hacer TDD, pero nadie las juntó mejor que "Pragmatic Unit Testing in Java With JUnit", de la serie Pragmatic Bookshelf. Hace un par de años que leí ese libro, y desde entonces creo que no hay forma que un desarrollador responsable pueda leer este libro sin entender que las pruebas unitarias son uno de los aspectos más importantes del desarrollo de software.

La excusa más preocupante que escucho es que es demasiado dificil probar mi código. Esto puede ser por dos motivos. Uno es que el código sea principalmente de interfaces de usuario (UI), y automatizar las pruebas de UI es muy dificil. Entiendo que la automatización de UI son bastantes complejas (¡y no imposibles!), pero se debería dedicar todo el esfuerzo en automatizar lo más posible: piensen en las pruebas de regresión. Si tienen una suite de pruebas completamente automatizada, incluyendo el comportamiento del UI, podrán hacer cambios al código con total confianza de no romper nada.

El segundo motivo de que el código es demasiado dificil de probar es que hicieron desastre con el diseño. Quizás la lógica y el código de UI están muy acoplados. Es por esto que TDD ayuda a mantener un diseño limpio, siguiendo las mejores prácticas. Usar JUnit es simple, y si puedo ejecutar toda la capa lógica por tener un diseño limpio, entonces podré probar toda la lógica que el UI va a usar. ¿Qué les falta el modelo de datos? Entonces pueden usar objetos mocks - ¡hay muchos frameworks para esto!

Para quienes todavía no leyeron el libro, les dejo un breve resumen de las excusas para no hacer TDD:

Escribir pruebas lleva mucho tiempo

Este es el principal motivo que dan los desarrolladores, y creo que se debe a cómo nos enseñan a desarrollar software. En general, nos hacen creer que la estapa de pruebas ocurre al final del proceso, y no durante todo el desarrollo.

TDD fomenta el modelo "pagar a medida que se avanza", en donde escribimos las pruebas mientras desarrollamos, por lo que no tenemos que meter tiempo al final del proceso para escribir todas las pruebas que podamos.

Y de todas formas, si no estás escribiendo pruebas a medida que avanzás, ¿cómo comprobás que el código se comporte como esperás? ¿Lo ejecutás manualmente? ¿No tiene más sentido invertir algo de este tiempo de pruebas manuales en escribir una prueba JUnit para esto? Quiero decir, en algún momento vas a tener que ejecutar esa porción de código - no va a quedar sin tocar el resto de la vida del producto.

De hecho, ocurren muchas más penalizaciones de tiempo si no se escriben pruebas unitarias. Vas a tener que gastar tiempo haciendo debug del código intentando averiguar porque algo no funciona. O vas a hacer un refactor, y luego darte cuenta que nada funciona como antes del refactor. Si tuvieras las pruebas unitarias, tendrías una base segura.

Lleva mucho tiempo ejecutar las pruebas

Si, puede llevarse bastante tiempo ejecutar pruebas que involucran a entidades externas, o pruebas de la interfaz de usuario. Pero se supone que hay más de un nivel de pruebas. Las pruebas unitarias deberían ejecutarse rápido, y podría haber un nivel de integración que también corra sin mucho impacto de tiempo. Si hay pruebas de integración que toman mucho tiempo, será cuestión de correrlas con menos frecuencia - quizás de manera nocturna. Esto no quiere decir que debemos ignorar las pruebas unitarias. Estas siempre deberían correr lo suficientemente ráipdo como para ser parte natural del proceso de software.

Mi trabajo no es probar el código

Todavía no sé en qué momento un desarrollador de software decide que puede tirar código contra la pared así nomás. Si nuestro trabajo fuera de "Codificador" quizás ahí tendríamos una mejor excusa. Pero nuestro trabajo consiste en desarrollar código que funcione, y por lo tanto necesitamos alguna forma de mostrar que nuestro código es funcional. Si a la gente de QA les cuesta encontrar bugs en nuestro código, va a ser maravilloso para nuestra reputación.

En realidad no sé cómo funciona el código, por lo que no puedo probarlo

Esta es dificil de tomar sin ser incrédulos. Si no entendemos cómo debería funcionar el código, no deberíamos empezar a programar. Primero debemos entender el requerimiento.

El libro tiene un par de excusas más, pero estos son las principales. ¿Qué excusas escucharon ustedes para no escribir pruebas?

Fuente: DosIdeas