El Desarrollo Guiado por Pruebas (TDD, por sus siglas en inglés) es una metodología de desarrollo de software que se centra en escribir pruebas antes de escribir el código funcional. Este enfoque ayuda a garantizar que el código sea robusto, mantenible y cumpla con los requisitos especificados.
Conceptos Clave de TDD
-
Red-Green-Refactor: Es el ciclo básico de TDD.
- Red: Escribir una prueba que falle.
- Green: Escribir el código mínimo necesario para que la prueba pase.
- Refactor: Mejorar el código manteniendo las pruebas en verde.
-
Pruebas Unitarias: Son pruebas que verifican el comportamiento de unidades individuales de código, como funciones o métodos.
-
Cobertura de Pruebas: Es una métrica que indica el porcentaje de código que está cubierto por las pruebas.
-
Mocking: Es una técnica para simular el comportamiento de objetos complejos o externos en las pruebas.
Ventajas del TDD
- Mejora la calidad del código: Al escribir pruebas primero, se asegura que el código cumple con los requisitos desde el principio.
- Facilita el mantenimiento: Las pruebas actúan como documentación viva del código.
- Reduce errores: Detecta errores en etapas tempranas del desarrollo.
Ejemplo Práctico de TDD
Vamos a desarrollar una función simple que calcule el factorial de un número utilizando TDD.
Paso 1: Escribir una Prueba que Falla (Red)
Primero, escribimos una prueba para una función factorial
que aún no existe.
import unittest class TestFactorial(unittest.TestCase): def test_factorial_of_zero(self): self.assertEqual(factorial(0), 1) def test_factorial_of_positive_number(self): self.assertEqual(factorial(5), 120) if __name__ == '__main__': unittest.main()
Al ejecutar esta prueba, obtendremos un error porque la función factorial
no está definida.
Paso 2: Escribir el Código Mínimo para Pasar la Prueba (Green)
Ahora, definimos la función factorial
para que pase la prueba.
def factorial(n): if n == 0: return 1 else: result = 1 for i in range(1, n + 1): result *= i return result
Paso 3: Refactorizar el Código
Revisamos el código para mejorar su claridad y eficiencia sin romper las pruebas.
def factorial(n): if n == 0: return 1 result = 1 for i in range(1, n + 1): result *= i return result
En este caso, el código ya es bastante claro y eficiente, por lo que no es necesario realizar más cambios.
Ejercicios Prácticos
-
Ejercicio 1: Escribir pruebas para una función que determine si un número es primo.
- Prueba:
test_is_prime
- Función:
is_prime
- Prueba:
-
Ejercicio 2: Escribir pruebas para una función que invierta una cadena.
- Prueba:
test_reverse_string
- Función:
reverse_string
- Prueba:
Soluciones
Ejercicio 1: Determinar si un número es primo
import unittest def is_prime(n): if n <= 1: return False for i in range(2, int(n**0.5) + 1): if n % i == 0: return False return True class TestIsPrime(unittest.TestCase): def test_is_prime(self): self.assertTrue(is_prime(5)) self.assertFalse(is_prime(4)) self.assertTrue(is_prime(13)) self.assertFalse(is_prime(1)) if __name__ == '__main__': unittest.main()
Ejercicio 2: Invertir una cadena
import unittest def reverse_string(s): return s[::-1] class TestReverseString(unittest.TestCase): def test_reverse_string(self): self.assertEqual(reverse_string("hello"), "olleh") self.assertEqual(reverse_string("world"), "dlrow") self.assertEqual(reverse_string(""), "") self.assertEqual(reverse_string("a"), "a") if __name__ == '__main__': unittest.main()
Conclusión
El Desarrollo Guiado por Pruebas es una metodología poderosa que puede mejorar significativamente la calidad y mantenibilidad del código. Al seguir el ciclo Red-Green-Refactor, los desarrolladores pueden asegurarse de que su código cumple con los requisitos y es robusto frente a cambios futuros. Practicar TDD regularmente puede ayudar a internalizar estos beneficios y hacer que el proceso de desarrollo sea más eficiente y menos propenso a errores.
Curso de Programación en Python
Módulo 1: Introducción a Python
- Introducción a Python
- Configuración del Entorno de Desarrollo
- Sintaxis de Python y Tipos de Datos Básicos
- Variables y Constantes
- Entrada y Salida Básica
Módulo 2: Estructuras de Control
- Sentencias Condicionales
- Bucles: for y while
- Herramientas de Control de Flujo
- Comprensiones de Listas
Módulo 3: Funciones y Módulos
- Definición de Funciones
- Argumentos de Función
- Funciones Lambda
- Módulos y Paquetes
- Visión General de la Biblioteca Estándar
Módulo 4: Estructuras de Datos
Módulo 5: Programación Orientada a Objetos
Módulo 6: Manejo de Archivos
- Lectura y Escritura de Archivos
- Trabajo con Archivos CSV
- Manejo de Datos JSON
- Operaciones de Archivos y Directorios
Módulo 7: Manejo de Errores y Excepciones
- Introducción a las Excepciones
- Manejo de Excepciones
- Lanzamiento de Excepciones
- Excepciones Personalizadas
Módulo 8: Temas Avanzados
- Decoradores
- Generadores
- Administradores de Contexto
- Concurrencia: Hilos y Procesos
- Asyncio para Programación Asíncrona
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias con unittest
- Desarrollo Guiado por Pruebas
- Técnicas de Depuración
- Uso de pdb para Depuración
Módulo 10: Desarrollo Web con Python
- Introducción al Desarrollo Web
- Fundamentos del Framework Flask
- Construcción de APIs REST con Flask
- Introducción a Django
- Construcción de Aplicaciones Web con Django
Módulo 11: Ciencia de Datos con Python
- Introducción a la Ciencia de Datos
- NumPy para Computación Numérica
- Pandas para Manipulación de Datos
- Matplotlib para Visualización de Datos
- Introducción al Aprendizaje Automático con scikit-learn