En el desarrollo del software, es común que una aplicación vaya evolucionando con el tiempo, a medida que se van aumentando funcionalidades y cambiando necesidades de negocio.
¿Cómo podemos garantizar la integridad de nuestras aplicaciones a medida que las vamos modificando?
Tener un buen juego de pruebas nos asegurará tener controlado qué queremos probar o validar.
¿Pero realmente nos interesa probarlo absolutamente todo?
La respuesta es no.
Pongamos como ejemplo el siguiente caso:
- Tenemos una función que recibe como parámetros nuestro nombre y fecha de cumpleaños.
- Con la fecha de nuestro cumpleaños, realizamos una consulta a un servicio web externo que nos dirá a qué signo del zodíaco pertenecemos.
- La función devolverá la división de la longitud de caracteres del signo del zodíaco, entre el número de vocales que tenga nuestro nombre.
Vemos que la lógica de la función se basa únicamente en un cálculo aritmético entre una longitud de un nombre y un número calculado. Para nada nos interesa probar en nuestros test si se realiza la llamada al servicio web de signos del zodíaco, o si este devuelve un valor correcto. Si realmente queremos probar dicha conexión, entonces realizaremos un test de integración entre ambos servicios.
Cuando desarrollemos, podemos crear nuestro módulo de código y, una vez hecho, crear varios test unitarios para validar los diferentes casos de uso que debe abarcar. Pero, ¿y si lo planteamos al revés y usamos los test unitarios para realizar el propio desarrollo?
Esto precisamente es lo que proponen prácticas de desarrollo como TDD (Test-Driven Development), que se basa en crear primero los test y después en refactorizar el código.
En concreto los pasos de TDD serían:
- Elegir un requisito a desarrollar
- Crear la prueba o test
- Ejecutar los test: falla
- Crear código específico para resolver el test
- Ejecutar de nuevo los test: pasa
- Refactorizar el código
- Ejecutar los test: pasa
Aplicando TDD sobre el problema planteado, realizaríamos los siguientes pasos:
1.- Elegimos el requisito de cálculo numérico a partir de un nombre y fecha.
2.- Creamos un test unitario en el que se pasará como parámetro:
- David
- 07/03/1985
Como sabemos que el siete de marzo es "Piscis" y David contiene 2 vocales, nuestra función devolverá 6/2=3.
3.- Ejecutamos el test, pero como no tenemos la lógica de la función desarrollada, el test fallará.
4.- Creamos el código de la función para resolver el requisito.
5.- Ejecutamos el test y funciona correctamente.
6.- Realizamos una refactorización del código, ya que es bastante probable que una primera implementación contenga líneas de código poco óptimo.
7.- Ejecutamos el test y funciona correctamente
Así, ¿qué es correcto? ¿Desarrollar los test unitarios una vez finalizado el desarrollo? ¿O bien aplicar TDD? Personalmente creo que, ni todo es blanco ni todo negro. Por descontado es una buena práctica realizar test unitarios, pero considero que es bueno realizarlos cuando ya tenemos una parte del desarrollo realizado, cuando tenemos la mente abierta y comprendemos el cien por cien del alcance del caso de uso.
¿Cómo realizáis vuestras pruebas unitarias? ¿Aplicáis TDD o esperáis a finalizar el desarrollo?
Nos podéis hacer llegar vuestros comentarios o dudas a la siguiente dirección hello@raona.com