A favor de los test unitarios

Hace unos días me dediqué a implementar en java una funcionalidad para un proyecto. Me puse a ello haciendo los test unitarios en paralelo al código que iba desarrollando, incluso un poco antes, de forma que pasaba el test, veía que fallaba y me ponía a arreglar.

Para hacer el código, me basé en una librería que estaba desarrollando otro compañero. Dicha librería estaba muy avanzada, pero no acabada, por lo que tenía algunos bugs e incluso código faltantes. Durante mi desarrollo y mis test, encontré algunos de esos fallos y faltantes, así que avisé a mi compañero, pero corregí o completé yo el código, por supuesto, haciendo adicionalmente otros test unitarios.

Por fin terminé la funcionalidad. Con los test encontré algunos fallos en mi propio código que también corregí y lo metí todo en CVS.

Al cuarto de hora de meterlo me aparece otro compañero y me dice … "revisa esos test que acabas de meter, que fallan….". ¡Vaya!, me quedé extrañado. Acababa de pasarlos y funcionaban todos. Los vuelvo a pasar en mi directorio de trabajo … y funcionan. Reviso que no me he olvidado de meter nada en CVS y todo correcto. Hago update, salen unos fuentes, paso el test … y falla. Revisando, revisando, compruebo que otro compañero más -el tercero-, ha tenido un despiste en una clase común y mi test ha fallado. Hablo con este compañero, que tiene el cambio reciente y en dos minutos queda solucionado el problema.

En total, algo menos de una semana codificando y otra semana larga que "perdí" haciendo los test. Queda además un "chivato" por si mi primer compañero decide más adelante cambiar su librería de forma que afecte a mi código.

Todo un poco aburrido hasta aquí y nada que se salga de lo normal, pero …. ¿qué podría haber pasado si no hubiera hecho test y hubiera hecho simplemente una prueba manual de mi código?. Veamos el posible futuro que posiblemente ya no es posible -espero-.

Si no hubiera hecho tests automáticos de prueba, sino simplemente unas pruebas manuales de mi código, habría visto igualmente los fallos y faltantes de la librería de mi primer compañero. Habría igualmente corregido y completado su código, pero sin hacer test unitarios. También habría encontrado mis propios errores al codificar. Una vez terminado todo lo habría metido en CVS.

Un cuarto de hora después NO habría venido mi segundo compañero a decir que los test fallan. El despiste de mi tercer compañero habría pasado desapercibido. Puede que él mismo se hubiera dado cuenta más adelante o no. Seamos tremendistas, supongamos que ese error no "canta" hasta bastante más adelante.

Seamos más tremendistas aun. Mi primer compañero, el de la librería, sigue su desarrollo de la librería y decide modificar o reorganizar el código que yo le hice y aunque el código sigue funcionando, ya no hace exactamente lo que yo quería que hiciera.

Mi código, que ya fue probado y no se ha probado más, ya no funciona. Hay un fallo por ahí que lo impide y una librería que se comporta algo distinto. Pero no hay tests unitarios que se pasan automáticamente en todos los compilados que lo indiquen.

El código llega al entorno de integración y pruebas. El responsable me reporta un "bug" varias semanas o meses después, cuando ya no tengo fresco el código que he hecho. Cuando consigo "turno", meto el debugger, miro y acabo encontrando el fallo que metió mi tercer compañero. Se lo comento. No se acuerda de por qué hizo ese cambio ni para qué servía. Tiene que revisar su código. Al día siguiente me viene con que no puede deshacer ese fallo, ya hay mucho código hecho basado en eso y si lo arregla, igual deja de funcionar. Meto en mi código una "ñapa" para que pase con el fallo de él. Compilo y decido recuperar la prueba manual que hice en su día.

Me ha costado encontrar el código de prueba manual que hice, porque no sé dónde demonios lo tenía. Lo paso otra vez a mano y veo que aquello no "furrula". Debugger al canto y veo, con mucho esfuerzo porque no tengo el código reciente, que la librería del primer compañero no hace lo que yo espero. Se lo comento y el, que tampoco tiene el código reciente, me dice que va a mirarlo. Al día siguiente me viene con que no va a cambiar ese código, porque está mejor así y además tiene mucho código hecho que se basa en eso. Le digo que me está haciendo la puñeta, me acabo peleando con él, no nos hablamos más y meto otra segunda ñapa en mi código para que funcione, que básicamente consiste en hacer una copia de su antigua librería en otro sitio.

Si hubiera hecho los test y mi compañero más adelante hubiera tocado la librería, el test hubiera "cantado" en el momento en el que él la toca. Hubiera sido más fácil llegar a un acuerdo cuando él está todavía haciendo el código y no tiene demasiado hecho basándose en ese cambio. Hubiera sido más receptivo a un "por favor, no me toques eso, que si no me deja de funcionar a mi".

La consecuencia de no hacer tests podría haber sido más agobio en la fase de pruebas, más tensión con los compañeros y soluciones más chapuzas en el código. Y posiblemente más tiempo perdido, ya que mi semana de hacer test es bastante menor que el tiempo que habría dedicado a : hacer unas pruebas manuales + debugger en el entorno de pruebas de un código que no tengo reciente + discusión con un compañero + recuperar el programa de pruebas manuales y volver a probar + debugger para el segundo fallo + discusión con otro compañero + tiempo de ñapear otra vez el código + tiempo que pierden otros compañeros mientras yo tengo ocupado el entorno de pruebas con el debugger.

Se que es difícil y que a veces es un poco pesado, pero viendo los fallos que ya han saltado por los test y lo que posiblemente hubiera pasado más adelante -excepto la pelea con el compañero, que en realidad estamos bien avenidos y no creo que la sangre hubiera llegado al rio-, creo que merece la pena. Siempre es mejor detectar un fallo y corregirlo con tu compañero en la tranquilidad de tu mesa de trabajo, cuando ambos teneis el código reciente y todavía no habeis hecho demasiado código basado en el fallo, que corregirlo en un entorno de pruebas, con la presión de un hito con el cliente cercano, con código del que ya no te acuerdas y sobre el que ya has construido muchas cosas y por tanto no puedes tocar con facilidad.

Y aunque siempre hay excepciones, también estoy convencido que un mismo código puede ser totalmente imposible de testear o se pueden hacer los test en una tarde dependiendo de cómo esté hecho el código.

Esta entrada fue publicada en junit. Guarda el enlace permanente.

11 respuestas a A favor de los test unitarios

  1. Blaxter dijo:

    La verdad que los test es la cosa más simple y a la vez más útil que te puedas encontrar, una maravilla :). En mi reciente pfc si no llega ser por ellos no habría terminado ni por asomo, y eso que trabajaba solo. En un equipo con varios trabajando en lo mismo… uff, me remito a tu post xD

    Últimamente lo que me estoy planteando mucho cómo abordar, es respecto a testear las GUIs, tanto de aplicaciones de escritorio, como en las aplicaciones Web. Diría que esa parte mejor obviarla pues un reconocimiento «humano» es mucho más efectivo. Pero de tener que hacerlo de forma manual a automatizarlo… habría una diferencia enorme.

  2. eynob dijo:

    buenisimo los test no solo ayudan a un mejor funcionamiento de la aplicacion sino tambien a las relaciones humanas, jajaja

    Buen en serio me parece muy interesante tu analisis y lo comparto.
    Ahora te hago una consulta, los test que haces son de dominio o tambien la base de datos, porque en mi experiencia estos son mas costosos y no les veo que sean de mas ayuda que los de dominio.

    Sobre lo que dice Blaxter tambien me parece interesante analizar que beneficios traen los test de GUI o si son un esfuerzo no tan redituable

    Saludos

  3. Chuidiang dijo:

    Hola:

    De test de base de datos andamos un poco peces, aunque en su día me encontré con sqlite. Es una especie de base de datos que va en fichero. Tiene conector para java. Para los test se puede crear un pequeño fichero sqlite con datos y usarlo para el test. Es algo que tengo pendiente de mirar con más calma.

    En cuanto a GUIs es una de las cosas comunmente aceptadas como que son muy difíciles de probar. Hay extensiones de JUnit y otras librerías que teóricamente ayudan, como squish, pero creo que ninguna ha dado el «salto a la fama».

    Se bueno.

  4. rfilgueiras dijo:

    En cuanto a los tests de GUI puede ser interesante la herramienta FIT y FITNESSE.

    Mira http://blog.riolambre.com/?p=79 para tener una idea.

    Saludos

  5. Chuidiang dijo:

    Hola rfilgueiras:

    He estado mirando lo de fitnesse. ¿cómo se puede usar eso con swing?. Aparentemente sólo es una forma cómoda de dar valores a las entradas para comprobar salidas, pero no veo la relación con swing.

    Se bueno.

  6. Dani dijo:

    Muy intersante, sí señor.
    Estoy por pasar éste post a los que nos tienen que dar permiso para utilizar junit y phpunit 🙁

    Saludos.

  7. Jordi dijo:

    Bravo por el post, sintetiza muy bien el objetivo que hay en testear. El tiempo que pierdes hoy lo recuperas mañana multiplicado por 10, seguro.

    Para testear código que opere con base de datos os recomiendo spring-mock.jar. En cada test inicializa una transaccion y hace un rollback en su finalización por lo que el estado de la DB se queda intacto.

    Un saludo.

  8. Pingback: programame.net

  9. Pingback: A favor de los tests unitarios - Noticias externas

  10. Hola!
    Mi aproximacion al testeo de GUI es muy simple, por si os sirve de algo mi experiencia:
    Siempre implemento un patron MVC, de tal manera que la Vista sea la que menos código tiene, cuanto menos mejor.
    Y lo único que quedaría es testear el Controlador, el cual perfectamente se puede testear automatizadamente.
    De esta manera la única parte testeada (la Vista) es mínima (también se puede testear con las herramientas que comentáis), reduciendo también las posibilidades de fallo.

    Un saludo
    Roberto

  11. Pingback: Diario de Programación » Testeando GUIs

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.