P3 · Segundo sprint: calidad

Publicado: semana 8 · Entrega: semana 11 (demo del sprint 2) · En equipo · Tag: p3

El sprint 2 sigue con las historias del backlog, y además pone el foco en cómo saben que el producto funciona. Al final de esta entrega, las reglas del negocio del cliente están cubiertas por pruebas unitarias y de propiedades, el código pasa TypeScript estricto y ESLint sin errores, y ningún cambio entró a main sin la revisión de otra persona.

Cubre las semanas 9 (pruebas unitarias, dobles de prueba, cobertura, TDD), 10 (pruebas basadas en propiedades, fuzzing y pruebas de mutación) y 11 (revisión de código, análisis estático, tipos y linters). La revisión de P3 vuelve a correr las de P1 y P2.

1. Qué entregan

Archivo Qué es
Las historias del sprint 2 En src/, con sus pruebas en *.test.ts
tsconfig.json Con "strict": true
eslint.config.js (o eslint.config.mjs) ESLint con typescript-eslint
package.json npm run check corre tipos, linter y pruebas con cobertura
Pruebas de propiedades Al menos 2, con fast-check
docs/estrategia-de-pruebas.md Qué prueban, cómo y qué no
docs/sprints/sprint-2.md Planificación, revisión (demo) y retrospectiva del sprint 2

Pruebas unitarias

Cada regla del negocio del cliente (las de los criterios de aceptación de P1) tiene pruebas que la verifican, incluidos sus casos límite: el último minuto antes del cierre y el primero después, el turno con un cupo y sin cupos, la cantidad 0 y la máxima. El nombre de la prueba cita la historia (test('a las 18:00 en punto ya cerró (HU-03)', ...)). Una prueba que no falla cuando se rompe la regla no verifica nada: importa qué verifican, no cuántas son.

Las pruebas no dependen del reloj real, de la red ni del orden en que corren: el instante se pasa como parámetro, la base de datos es una en memoria o un archivo temporal (semana 9).

Pruebas basadas en propiedades

Al menos 2 propiedades con fast-check, sobre reglas que importan (no sobre a + b === b + a). Van en archivos *.test.ts que importan fast-check con import fc from 'fast-check' y usan fc.assert(fc.property(...)), como en la semana 10. Ideas: “el total nunca supera el precio de lista”, “pedir una unidad más nunca cuesta menos”, “nunca se acepta una reserva después del cierre”, “cancelar y volver a reservar deja los cupos como estaban”, “convertir y volver a convertir da lo mismo”.

Cobertura

La cobertura de líneas de los archivos de src/ tiene que ser de al menos 70 %. Se mide con el runner de Node:

node --test --experimental-test-coverage --test-coverage-include='src/**' --test-coverage-lines=70

Pongan ese comando (o uno equivalente) en npm run check. La revisión automática mide por su cuenta y cuenta también los archivos de src/ que ninguna prueba carga, con todas sus líneas sin cubrir (Node no los incluye en su reporte; un archivo que solo declara tipos no cuenta). Por eso su número puede ser un poco más bajo que el de Node.

¿Por qué 70 %? Es un mínimo, no una meta. Alcanza para obligar a probar las reglas del negocio y las rutas de la API, y deja fuera lo que cuesta probar y casi no tiene lógica (el archivo que levanta el servidor). Google, por ejemplo, considera 60 % aceptable, 75 % encomiable y 90 % ejemplar (Code Coverage Best Practices, 2020). Y la cobertura dice qué líneas corrieron, no qué se verificó: una prueba sin aserciones cubre igual. Para saber si sus pruebas detectan errores, corran Stryker sobre el módulo de reglas (semana 10) y comenten el resultado en la estrategia de pruebas.

TypeScript estricto y ESLint

  • tsconfig.json dice "strict": true explícitamente, sin apagar ninguna de sus partes ("strictNullChecks": false, "noImplicitAny": false, …), y tsc --noEmit no da errores. Ningún archivo de src/ lleva @ts-nocheck.
  • La configuración de ESLint (eslint.config.js o eslint.config.mjs; ESLint del contenedor no carga eslint.config.ts) usa typescript-eslint, y eslint . --max-warnings 0 no da errores ni avisos. Recomendamos tseslint.configs.strictTypeChecked, como en la semana 11. Si apagan una regla, el comentario dice por qué.
  • npm run check corre los tres pasos (tipos, linter, pruebas con cobertura) y es lo mismo que correrá el pipeline de P4.

Revisión de código

Todos los pull requests integrados a main tienen la revisión de una persona distinta de quien lo abrió (una aprobación, un pedido de cambios o comentarios). La revisión es real: comentarios sobre el diseño, las pruebas que faltan, los nombres; no solo “LGTM”. Desde el primer pull request, nada entra a main por fuera de un pull request: integren con merge commit o squash (no con rebase, ver P2).

docs/estrategia-de-pruebas.md

  • ## Qué probamos: los niveles de prueba (unitarias, de la API, manuales) y qué cubre cada uno, con los archivos.
  • ## Pruebas basadas en propiedades: cada propiedad, en español, y por qué importa.
  • ## Cobertura: el número que dio, qué no está cubierto y por qué; si corrieron Stryker, el puntaje de mutación y qué hicieron con los mutantes que sobrevivieron.
  • ## Qué no probamos: lo que queda sin pruebas automáticas, a propósito, y cómo lo verifican.

docs/sprints/sprint-2.md

Las mismas tres secciones que el sprint 1 (## Planificación, ## Revisión, ## Retrospectiva). En la planificación, digan si se cumplieron las acciones de la retrospectiva del sprint 1.

2. Revisión automática

Dentro del contenedor del curso, desde la carpeta del repositorio del equipo, clonado dentro de la carpeta del curso (P1, sección 1):

cd /work/equipo-nombre
make -f /work/projects/p3-calidad/Makefile check

Corre las reglas de P1 y P2 y estas:

Regla Qué revisa
P3-TSC tsconfig.json con "strict": true y sin apagar sus partes; sin @ts-nocheck en src/; tsc --noEmit sin errores
P3-ESLINT eslint.config.js o .mjs con typescript-eslint; eslint . --max-warnings 0 sin errores ni avisos
P3-NPM-CHECK npm run check termina bien
P3-COBERTURA Cobertura de líneas de src/ de al menos 70 %, contando los archivos que ninguna prueba carga
P3-PROPIEDADES Al menos 2 fc.assert en archivos *.test.ts que importan fast-check
P3-ESTRATEGIA docs/estrategia-de-pruebas.md con sus cuatro secciones
P3-SPRINT-2 docs/sprints/sprint-2.md con sus tres secciones y al menos una historia que existe
P3-HISTORIA-MAIN Después del primer pull request, todos los commits de la historia principal de main son merges de pull requests
P3-REVISIONES Con gh (sesión iniciada y red): cada pull request integrado a main tiene una revisión de alguien distinto de su autor

P3-REVISIONES necesita la CLI de GitHub con sesión (gh auth login, en su computadora) y que origin apunte a GitHub. Sin eso queda como aviso y vale P3-HISTORIA-MAIN; el docente corre la revisión con gh, así que una revisión que falta se ve igual.

3. Cómo entregar

Con el tag p3, como en P1. La demo del sprint 2 con el cliente es en la semana 11.

4. Consejos y errores comunes

  • Pruebas que repiten el código. Si el valor esperado de una prueba se calcula con la misma fórmula que el código, la prueba no puede fallar. El valor esperado sale del criterio de aceptación, calculado a mano.
  • Perseguir el número de cobertura. Probar los getters para llegar a 70 % no ayuda; probar los casos límite de una regla sí. Si están lejos del mínimo, miren qué módulo no tiene pruebas, no qué línea.
  • Pruebas que fallan a ciertas horas. Una prueba que usa new Date() pasa en la mañana y falla en la noche (o al revés). Pasen el reloj como parámetro.
  • Revisiones de trámite. Una aprobación sin comentarios en un pull request de 600 líneas es una señal de que nadie lo leyó. Pull requests pequeños se revisan mejor (semana 11).
  • Apagar las reglas que molestan. // eslint-disable en todo el archivo o as any por todos lados esconden lo que el linter encontró. Si una regla no sirve para el proyecto, apáguenla en la configuración, con un comentario.
  • Con IA. Una herramienta escribe pruebas muy rápido, y muchas veces prueban lo que el código hace y no lo que debería hacer. Revisen cada valor esperado contra el criterio de aceptación, y pidan propiedades en vez de ejemplos: una propiedad falsa la descarta fast-check. Las pruebas de mutación dicen si las pruebas generadas detectan algo.