En este tema veremos cómo sostener un ritmo de trabajo práctico con TDD. No alcanza con conocer el ciclo rojo, verde y refactor: también necesitamos ejecutar pruebas con frecuencia, mantener cambios pequeños y registrar avances en commits claros.
El objetivo es trabajar de forma que cada paso sea verificable, reversible y fácil de revisar.
Un ciclo sano suele verse así:
Trabajaremos con una función para calcular puntos de fidelidad. La regla inicial será:
Usaremos este ejemplo para mostrar cuándo ejecutar pruebas y cuándo conviene crear un commit.
Comenzamos con un caso simple.
Archivo a crear: tests/test_fidelidad.py
from fidelidad import calcular_puntos
def test_calcula_un_punto_por_cada_diez_unidades():
puntos = calcular_puntos(total_compra=50)
assert puntos == 5
Ejecutamos la prueba.
python -m pytest tests/test_fidelidad.py
En esta etapa esperamos rojo: el módulo o la función todavía no existen.
Creamos el código necesario.
Archivo a crear: src/fidelidad.py
def calcular_puntos(total_compra):
return total_compra // 10
Ejecutamos otra vez:
python -m pytest tests/test_fidelidad.py
Si pasa, estamos en verde para este comportamiento.
Si el cambio es coherente y la prueba pasa, puede ser momento de guardar el avance.
git status
git add src/fidelidad.py tests/test_fidelidad.py
git commit -m "Agrega cálculo básico de puntos de fidelidad"
El commit describe una unidad de comportamiento, no una sesión entera de trabajo.
Agregamos un borde para confirmar que una compra de 59 genera 5 puntos, no 6.
Archivo a modificar: tests/test_fidelidad.py
def test_puntos_redondean_hacia_abajo():
puntos = calcular_puntos(total_compra=59)
assert puntos == 5
Ejecutamos solo el archivo de pruebas del tema actual:
python -m pytest tests/test_fidelidad.py
Esta prueba probablemente ya pase. Aun así, documenta una decisión importante.
Durante el ciclo corto conviene ejecutar primero la prueba o el archivo relacionado con el cambio actual.
python -m pytest tests/test_fidelidad.py::test_puntos_redondean_hacia_abajo
Esto da retroalimentación rápida. Luego, antes de cerrar un cambio, ejecutamos una suite más amplia.
Agregamos una validación.
Archivo a modificar: tests/test_fidelidad.py
import pytest
def test_total_compra_no_puede_ser_negativo():
with pytest.raises(ValueError, match="El total no puede ser negativo"):
calcular_puntos(total_compra=-10)
Esta prueba debe fallar con la implementación actual.
Agregamos el mínimo código para pasar la nueva prueba.
Archivo a modificar: src/fidelidad.py
def calcular_puntos(total_compra):
if total_compra < 0:
raise ValueError("El total no puede ser negativo")
return total_compra // 10
Ejecutamos primero la prueba específica y luego el archivo completo.
python -m pytest tests/test_fidelidad.py::test_total_compra_no_puede_ser_negativo
python -m pytest tests/test_fidelidad.py
No siempre hace falta ejecutar todo después de cada tecla, pero sí conviene hacerlo en momentos claros.
python -m pytest
Si aparece una constante de negocio, podemos darle nombre.
Archivo a modificar: src/fidelidad.py
UNIDADES_POR_PUNTO = 10
def calcular_puntos(total_compra):
if total_compra < 0:
raise ValueError("El total no puede ser negativo")
return total_compra // UNIDADES_POR_PUNTO
Después del refactor ejecutamos:
python -m pytest tests/test_fidelidad.py
python -m pytest
Ahora el cambio incluye validación y una mejora de nombres. Si la suite está en verde, el commit puede ser:
git status
git add src/fidelidad.py tests/test_fidelidad.py
git commit -m "Valida total negativo en cálculo de puntos"
Si el refactor fue pequeño y relacionado, puede quedar en el mismo commit. Si fue más amplio, conviene separarlo.
cambios o fix.
pytest permite ejecutar subconjuntos de pruebas.
python -m pytest tests/test_fidelidad.py
python -m pytest tests/test_fidelidad.py -q
python -m pytest -k "fidelidad"
python -m pytest -x
-q reduce salida, -k filtra por nombre y -x detiene
la ejecución en el primer fallo.
La retroalimentación no viene solo de las pruebas. También puede venir de:
Cada señal dice algo sobre el diseño o sobre el ritmo de trabajo.
Un flujo práctico puede dividirse así:
| Momento | Acción |
|---|---|
| Mientras escribo código | Ejecutar la prueba específica |
| Después de pasar a verde | Ejecutar el archivo de pruebas relacionado |
| Después de refactorizar | Ejecutar la suite completa |
| Antes de commit | Revisar cambios y ejecutar pruebas relevantes |
Antes de crear un commit, conviene revisar qué cambió.
git status
git diff
La revisión ayuda a detectar cambios accidentales, código de depuración o archivos que no deberían incluirse.
python -m pytest tests/test_fidelidad.py
# rojo
# implementar mínimo
python -m pytest tests/test_fidelidad.py
# verde
# refactor pequeño
python -m pytest
# verde
git status
git diff
git add src/fidelidad.py tests/test_fidelidad.py
git commit -m "Agrega regla de puntos de fidelidad"
El objetivo es que cada sesión deje el sistema en un estado entendible.
Practicá una sesión completa de TDD con una función calcular_nivel_cliente.
TDD funciona mejor cuando se practica con un ritmo sostenido: pruebas pequeñas, ejecución frecuente, refactors controlados y commits claros. Esa disciplina reduce el riesgo de cada cambio y facilita corregir el rumbo cuando algo falla.
En el próximo tema veremos cómo trabajar con TDD en código existente usando caracterización antes de cambiar comportamiento.