El Desarrollo Guiado por Pruebas (Test-Driven Development o TDD) es una práctica de desarrollo de software que invierte el orden tradicional de la programación. En lugar de escribir el código de producción primero y las pruebas después (si es que se escriben), TDD dicta que las pruebas deben escribirse antes que el código que las hará pasar. Esta disciplina es fundamental en Extreme Programming (XP) por su impacto directo en la calidad y el diseño del software.
La idea central de TDD es que una prueba automatizada define el comportamiento esperado de una pequeña pieza de funcionalidad antes de que esta exista. La prueba actúa como una especificación ejecutable. Al escribir la prueba primero, el desarrollador se obliga a pensar en los requisitos y el comportamiento deseado desde la perspectiva del "cliente" de ese código (otra función, otro módulo, etc.).
Este enfoque tiene varias implicaciones profundas:
TDD se desarrolla en un ciclo muy corto y repetitivo conocido como "Red-Green-Refactor". Cada ciclo dura solo unos minutos y se enfoca en una pequeña pieza de comportamiento.
Este ciclo se repite para cada nueva pieza de funcionalidad, construyendo gradualmente una base de código robusta y cubierta por un conjunto completo de pruebas automáticas.
La adopción de TDD, aunque requiere disciplina, aporta beneficios significativos al proceso de desarrollo:
Veamos un ejemplo de TDD para crear una función simple que suma dos números en Python, usando el framework de pruebas `unittest`.
Primero, creamos un archivo de prueba `test_calculadora.py` y escribimos una prueba para una función `sumar` que aún no existe.
import unittest
# Aún no importamos la calculadora porque no existe
class TestCalculadora(unittest.TestCase):
def test_sumar_dos_numeros(self):
"""Prueba que la función sumar puede sumar dos números positivos."""
from calculadora import sumar # Intentamos importar la función
resultado = sumar(2, 3)
self.assertEqual(resultado, 5)
if __name__ == '__main__':
unittest.main()
Si ejecutamos esta prueba, fallará con un `ModuleNotFoundError` (o `ImportError`) porque `calculadora.py` no existe. Esto es nuestro estado "Red".
Ahora, creamos el archivo `calculadora.py` y escribimos el código más simple posible para que la prueba pase.
# calculadora.py
def sumar(a, b):
return a + b
Si volvemos a ejecutar `test_calculadora.py`, la prueba ahora pasará. Hemos alcanzado el estado "Green".
En este caso, la función `sumar` es tan simple que no hay mucho que refactorizar. Sin embargo, podríamos pensar en mejorarla. Por ejemplo, ¿qué pasa si queremos añadir un docstring para explicar lo que hace?
# calculadora.py (refactorizado)
def sumar(a, b):
"""Suma dos números y devuelve el resultado."""
return a + b
Después de esta refactorización, volvemos a ejecutar las pruebas. Deben seguir pasando, lo que nos confirma que no hemos roto nada. Ahora el ciclo está completo y podemos proceder a escribir la siguiente prueba para un nuevo comportamiento (por ejemplo, sumar números negativos, sumar cero, etc.).