Módulo 8: Proyecto Integrador — Test Suite Completa con TDD

Planning Spec-First: Diseñar desde los Tests

Planning Spec-First: Diseñar desde los Tests

Descripción de la cápsula

Antes de escribir una línea de implementación, vas a diseñar la TaskFlow API desde los tests. Esta cápsula es pura planificación: descomponer features en user stories, mapear cada story a specs testeables, definir los nombres exactos de los tests que escribirás, y crear la estructura de archivos vacía.

No implementas nada aquí. Diseñas el contrato entre lo que la aplicación debe hacer y cómo lo validarás. Al terminar, tendrás un blueprint completo que guía todo el desarrollo posterior.


¿Por Qué Planning Antes de Código?

El problema de "empezar a codear"

Cuando empiezas a implementar sin planificación, tiendes a:

  • Escribir features que no cubren todos los casos necesarios
  • Descubrir requirements a mitad de camino
  • Terminar con tests que no reflejan el comportamiento esperado
  • Perder tiempo refactorizando porque la arquitectura no anticipó ciertos casos

El enfoque spec-first

En spec-first, defines los tests como especificación antes de implementar:

  • Los tests son el contrato: "la app debe hacer X, Y, Z"
  • Claude Code implementa contra ese contrato
  • No hay ambigüedad: el test pasa o falla
  • La feature decomposition te obliga a pensar en edge cases antes de escribir código

Feature Decomposition: Romper Features en Specs

Qué es feature decomposition

Feature decomposition es dividir un feature grande ("autenticación") en specs individuales y testeables. Cada spec es un test con un nombre que describe exactamente qué debe pasar.

Ejemplo:

Feature grande: "Autenticación"
  → Spec 1: register con email válido crea usuario
  → Spec 2: register con email duplicado falla
  → Spec 3: login con credenciales correctas retorna token
  → Spec 4: login con password incorrecto falla
  ...

Cómo decomponer

Para cada feature, pregúntate:

  1. ¿Cuál es el happy path?
  2. ¿Qué errores pueden ocurrir?
  3. ¿Qué edge cases existen?
  4. ¿Qué validaciones deben aplicarse?

Cada respuesta se convierte en el nombre de un test.


User Stories → Test Specs: El Mapeo

Feature 1: Autenticación

User stories:

  • Como usuario, quiero registrarme con email y password para tener una cuenta
  • Como usuario, quiero iniciar sesión con mis credenciales para obtener un token
  • Como usuario, quiero que mi token sea válido para acceder a endpoints protegidos
  • Como usuario, quiero que credenciales inválidas sean rechazadas

Test specs (8-10 tests):

#Nombre del testQué valida
1test_register_creates_user_with_valid_email_and_passwordRegistro exitoso crea usuario y retorna datos (sin password)
2test_register_duplicate_email_failsEmail ya registrado → ValueError
3test_register_invalid_email_raisesEmail mal formado → ValueError
4test_register_weak_password_raisesPassword que no cumple requisitos → ValueError
5test_login_returns_token_for_valid_credentialsLogin exitoso retorna token string
6test_login_wrong_password_raisesPassword incorrecto → ValueError
7test_login_nonexistent_user_raisesUsuario no existe → ValueError
8test_validate_token_returns_user_for_valid_tokenToken válido retorna datos del usuario
9test_validate_token_raises_for_invalid_tokenToken inválido o expirado → ValueError
10test_password_is_hashed_on_registerEl password nunca se almacena en texto plano

Feature 2: Equipos (Teams)

User stories:

  • Como usuario, quiero crear un equipo para organizar tareas con otros
  • Como owner, quiero agregar miembros a mi equipo
  • Como usuario, quiero listar los equipos a los que pertenezco

Test specs (6-8 tests):

#Nombre del testQué valida
1test_create_team_returns_team_with_ownerCrear equipo retorna equipo con el creator como owner
2test_create_team_requires_authenticated_userSin token → 401
3test_add_member_adds_user_to_teamAgregar miembro exitosamente
4test_add_member_requires_owner_permissionSolo owner puede agregar miembros
5test_add_member_duplicate_raisesAgregar miembro ya existente → error
6test_list_teams_returns_user_teamsListar equipos retorna solo los del usuario
7test_list_team_members_returns_correct_usersListar miembros retorna owner + miembros
8test_get_team_by_id_returns_team_or_404Obtener equipo por ID, 404 si no existe

Feature 3: Tareas (Tasks)

User stories:

  • Como usuario, quiero crear tareas dentro de un equipo
  • Como usuario, quiero asignar tareas a miembros del equipo
  • Como usuario, quiero cambiar el estado de las tareas (pendiente → en progreso → completada)
  • Como usuario, quiero filtrar tareas por estado, prioridad y asignee

Test specs (10-12 tests):

#Nombre del testQué valida
1test_create_task_returns_task_in_teamCrear tarea retorna tarea con datos correctos
2test_create_task_requires_team_membershipUsuario no miembro no puede crear tarea
3test_get_task_by_id_returns_task_or_404Obtener tarea por ID
4test_update_task_modifies_fieldsActualizar título, descripción, etc.
5test_delete_task_removes_from_teamEliminar tarea la quita del equipo
6test_assign_task_to_team_member_succeedsAsignar tarea a miembro del equipo
7test_assign_task_to_non_member_failsAsignar a no-miembro falla
8test_transition_pending_to_in_progress_succeedsTransición válida pending → in_progress
9test_transition_in_progress_to_completed_succeedsTransición válida in_progress → completed
10test_filter_tasks_by_status_returns_matchingFiltrar por status retorna solo las que coinciden
11test_filter_tasks_by_priority_returns_matchingFiltrar por prioridad
12test_filter_tasks_by_assignee_returns_matchingFiltrar por asignee

Feature 4: Business Logic

User stories:

  • Como sistema, debo validar que las transiciones de estado sean válidas (no retroceder)
  • Como sistema, debo validar permisos: solo el asignee puede completar una tarea
  • Como usuario, quiero ver estadísticas del equipo (tareas por estado, tasa de completación)

Test specs (6-8 tests):

#Nombre del testQué valida
1test_transition_completed_to_in_progress_raisesNo se puede retroceder completed → in_progress
2test_transition_pending_to_completed_raisesNo se puede saltar pending → completed (debe pasar por in_progress)
3test_only_assigned_user_can_complete_taskSolo el asignee puede marcar como completed
4test_team_owner_can_add_membersPermiso de owner para agregar
5test_get_team_stats_returns_tasks_by_statusStats retornan conteo por status
6test_get_team_stats_completion_rateCompletation rate calculado correctamente
7test_unassigned_task_can_be_completed_by_any_memberTarea sin asignee: cualquier miembro puede completar
8test_invalid_status_transition_raisesTransición a status inválido → ValueError

Crear la Estructura de Tests (Archivos Vacíos)

Estructura de directorios

taskflow/
├── app/
│   └── ... (estructura de la app)
├── tests/
│   ├── conftest.py
│   ├── unit/
│   │   ├── conftest.py
│   │   ├── test_auth.py
│   │   ├── test_teams.py
│   │   ├── test_tasks.py
│   │   └── test_rules.py
│   ├── integration/
│   │   ├── conftest.py
│   │   ├── test_auth_endpoints.py
│   │   ├── test_team_endpoints.py
│   │   └── test_task_endpoints.py
│   └── e2e/
│       ├── conftest.py
│       └── test_flows.py

Archivo: tests/unit/test_auth.py (estructura vacía)

# tests/unit/test_auth.py
# Tests para auth service (registro, login, validación de token)

def test_register_creates_user_with_valid_email_and_password():
    pass

def test_register_duplicate_email_fails():
    pass

def test_register_invalid_email_raises():
    pass

def test_register_weak_password_raises():
    pass

def test_login_returns_token_for_valid_credentials():
    pass

def test_login_wrong_password_raises():
    pass

def test_login_nonexistent_user_raises():
    pass

def test_validate_token_returns_user_for_valid_token():
    pass

def test_validate_token_raises_for_invalid_token():
    pass

def test_password_is_hashed_on_register():
    pass

Archivo: tests/unit/test_teams.py

# tests/unit/test_teams.py

def test_create_team_returns_team_with_owner():
    pass

def test_add_member_adds_user_to_team():
    pass

def test_add_member_requires_owner_permission():
    pass

def test_add_member_duplicate_raises():
    pass

def test_list_teams_returns_user_teams():
    pass

def test_list_team_members_returns_correct_users():
    pass

def test_get_team_by_id_returns_team_or_404():
    pass

Archivo: tests/unit/test_tasks.py

# tests/unit/test_tasks.py

def test_create_task_returns_task_in_team():
    pass

def test_create_task_requires_team_membership():
    pass

def test_get_task_by_id_returns_task_or_404():
    pass

def test_update_task_modifies_fields():
    pass

def test_delete_task_removes_from_team():
    pass

def test_assign_task_to_team_member_succeeds():
    pass

def test_assign_task_to_non_member_fails():
    pass

def test_filter_tasks_by_status_returns_matching():
    pass

def test_filter_tasks_by_priority_returns_matching():
    pass

def test_filter_tasks_by_assignee_returns_matching():
    pass

Archivo: tests/unit/test_rules.py

# tests/unit/test_rules.py
# Business logic: transiciones de estado, permisos, stats

def test_transition_completed_to_in_progress_raises():
    pass

def test_transition_pending_to_completed_raises():
    pass

def test_only_assigned_user_can_complete_task():
    pass

def test_get_team_stats_returns_tasks_by_status():
    pass

def test_get_team_stats_completion_rate():
    pass

def test_unassigned_task_can_be_completed_by_any_member():
    pass

def test_invalid_status_transition_raises():
    pass

Archivos de integration (estructura)

Para integration, los tests validan endpoints con TestClient. Los nombres reflejan el comportamiento HTTP:

  • test_register_endpoint_returns_201_and_user
  • test_login_endpoint_returns_200_and_token
  • test_protected_endpoint_returns_401_without_token
  • test_create_team_endpoint_returns_201
  • test_add_member_endpoint_returns_200
  • test_create_task_endpoint_returns_201
  • etc.

(En la próxima cápsula implementarás estos con código real.)


Priorización: Core First, Business Logic Después

Orden recomendado

No implementas todos los tests en paralelo. Sigues un orden que minimiza dependencias:

Fase 1 — Core (primero):

  • Auth (todo el módulo): sin auth no hay usuarios, sin usuarios no hay equipos
  • Teams (crear, listar): sin equipos no hay tareas
  • Tasks (CRUD básico): crear, leer, actualizar, eliminar

Fase 2 — Business logic:

  • Transiciones de estado
  • Permisos (quién puede hacer qué)
  • Stats y filtros
  • Edge cases

Por qué este orden

  • Auth es la base: cada endpoint protegido depende del token
  • Teams es la segunda capa: las tareas pertenecen a equipos
  • Tasks CRUD es el núcleo funcional: sin esto la app no hace nada útil
  • Business logic refina el comportamiento pero presupone que el CRUD existe

Planning Checklist

Antes de pasar a la implementación, verifica que tienes:

  • Lista completa de tests por feature (auth, teams, tasks, business logic)
  • Archivos de test creados con pass y nombres descriptivos
  • Orden de implementación definido (auth → teams → tasks → rules)
  • Claridad sobre qué tests son unit vs integration vs E2E

Resumen

  • La feature decomposition convierte "quiero auth" en 10 specs concretos
  • Cada user story se mapea a tests con nombres que documentan el comportamiento
  • Creas la estructura de archivos vacía antes de implementar
  • Priorizas: core features (auth, teams, tasks CRUD) primero; business logic después
  • Esta cápsula es solo planificación — en la siguiente empieza el TDD real

Próxima cápsula: Core Features con TDD — implementar auth, teams y tasks ciclo por ciclo.


Módulo 8, Cápsula 02 — Testing with Claude Code Guide