En este reto vas a trabajar en parejas para extender la funcionalidad de la aplicación disponible en minireto-03-uvl-tdd e implementar la función classify_model_size(), que está tan solo esbozada en catalog.py. Lo haréis mediante ciclos pequeños Red-Green-Refactor usando TDD.
Las reglas que tendrás que implementar en la función son las siguientes:
- de 1 a 5 características:
tiny - de 6 a 15:
small - de 16 a 30:
medium - 31 o más:
large - un número menor que 1 es inválido
Pero recuerda que vamos a usar TDD, así que no debéis implementar todas las reglas de una vez. Iréis siguiendo el ciclo Red-Green-Refactor para añadir una prueba pequeña, comprobar que falla, escribir el código mínimo, comprobar que pasa y revisar el diseño.
Debéis ir alternando quién escribe el código en cada ciclo (al estilo pair-programming). Y además tenéis que ir documentando cada ciclo en el archivo DECISIONES_TDD.md disponible en el repositorio.
Preparar el entorno
- Descarga o clona minireto-03-uvl-tdd.
- Abre una terminal en la carpeta del proyecto.
- Crea un entorno virtual.
- Actívalo.
- Instala las dependencias.
- Ejecuta la batería inicial.
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -r requirements-dev.txt
python3 -m pytest
Debe fallar test_one_feature_is_tiny porque classify_model_size() lanza NotImplementedError. Ese rojo inicial confirma que la prueba detecta la ausencia de comportamiento.
Ciclo 1: el caso más pequeño
Red
La prueba inicial expresa que un modelo con una característica es tiny. Ejecútala y conserva el fallo observado en el diario.
python3 -m pytest tests/test_size.py -q
Green Escribe el código mínimo que haga pasar ese único caso:
def classify_model_size(feature_count: int) -> str:
return "tiny"
Ejecuta las pruebas. El caso pasa. La implementación todavía es incompleta, pero TDD no exige anticipar reglas que ninguna prueba ha expresado.
Refactor No hay duplicación ni estructura que mejorar. Documenta que no se refactoriza todavía.
Ciclo 2: validar entradas imposibles
Red Añade una prueba que exija rechazar cero características:
def test_zero_features_is_invalid():
with pytest.raises(ValueError):
classify_model_size(0)
Green
def classify_model_size(feature_count: int) -> str:
if feature_count < 1:
raise ValueError("feature_count debe ser positivo")
return "tiny"
Refactor La validación está expresada claramente. No hace falta cambiarla.
Ciclo 3: primer valor límite
La categoría tiny termina en 5 y small comienza en 6. Estos dos valores forman una pareja de límites especialmente informativa.
Red
def test_five_features_is_tiny():
assert classify_model_size(5) == "tiny"
def test_six_features_is_small():
assert classify_model_size(6) == "small"
Green
def classify_model_size(feature_count: int) -> str:
if feature_count < 1:
raise ValueError("feature_count debe ser positivo")
if feature_count <= 5:
return "tiny"
return "small"
Refactor La estructura sigue siendo pequeña y legible. Comprueba toda la batería antes de continuar.
Ciclos siguientes: 15/16 y 30/31
Repite el mismo proceso con los límites entre small y medium y entre medium y large.
def test_fifteen_features_is_small():
assert classify_model_size(15) == "small"
def test_sixteen_features_is_medium():
assert classify_model_size(16) == "medium"
def test_thirty_features_is_medium():
assert classify_model_size(30) == "medium"
def test_thirty_one_features_is_large():
assert classify_model_size(31) == "large"
La implementación final puede quedar así:
def classify_model_size(feature_count: int) -> str:
if feature_count < 1:
raise ValueError("feature_count debe ser positivo")
if feature_count <= 5:
return "tiny"
if feature_count <= 15:
return "small"
if feature_count <= 30:
return "medium"
return "large"
Refactor de las pruebas con parametrización
Las pruebas de límites contienen la misma estructura. Cuando todas pasan, puedes reducir la repetición usando pytest.mark.parametrize.
@pytest.mark.parametrize(
("feature_count", "expected"),
[
(1, "tiny"),
(5, "tiny"),
(6, "small"),
(15, "small"),
(16, "medium"),
(30, "medium"),
(31, "large"),
],
)
def test_classify_model_size(feature_count, expected):
assert classify_model_size(feature_count) == expected
Una vez comprobado que la prueba parametrizada cubre los mismos casos y que toda la batería sigue pasando, elimina las pruebas individuales que ahora resulten redundantes. Mantén separadas las pruebas que verifican comportamientos diferentes, como el lanzamiento de excepciones.
Validación final
python3 -m pytest -q
Todas las pruebas deben pasar. Revisa DECISIONES_TDD.md y comprueba que cada ciclo explica qué caso se añadió, por qué, qué código mínimo se escribió y qué refactor se realizó o se descartó.