Herramientas de usuario

Herramientas del sitio


clase:daw:daw-proyecto:tema05

¡Esta es una revisión vieja del documento!


5. Automatizando el proyecto con IA

Objetivo del tema: que la calidad la vigilen tests que genera la IA en los cuatro niveles (arquitectura, unitarios, API y E2E) y que ningún issue llegue a develop sin pasar una revisión. Al acabar, cerrar un issue es /git-flow finalizar y todo lo demás ocurre solo, y un CRUD nuevo es una sola orden.

Tests de arquitectura con ArchUnit

Las reglas de arquitectura (las de Programación y DWS: capas, nombres, sin ciclos, domain sin Spring) las hace cumplir ArchUnit con tests que fallan cuando una clase está donde no debe. Lo nuevo es que los escribe la IA a partir de las reglas en castellano:

/crear-test-arquitectura
- Las clases de controller solo dependen de domain.
- Las de persistence solo dependen de domain.
- Nada en domain importa org.springframework ni jakarta.persistence.
- Los controladores acaban en Controller y están en ..controller..
- Los repositorios de persistence acaban en RepositoryImpl e implementan una interfaz de domain.
- Sin ciclos entre paquetes.

Cada test lleva en su @DisplayName y en un comentario qué comprueba, por qué y las excepciones:

@Test
@DisplayName("domain no depende de Spring: el dominio tiene que compilar y probarse sin el framework")
void domainSinSpring() {
    noClasses().that().resideInAPackage("..domain..")
        .should().dependOnClassesThat().resideInAPackage("org.springframework..")
        .check(clases);
}

No hay un documento aparte con la arquitectura. Mantener un Markdown sincronizado con los tests es un trabajo que nadie hace, así que la fuente de verdad son los tests con su descripción. Para cambiar una regla se le pide a la skill que cambie el test. Cuando se añade una regla que el código actual aún no cumple, FreezingArchRule.freeze(regla) congela las violaciones existentes y solo falla con las nuevas.

Tests unitarios con JUnit

Los tests unitarios prueban la lógica del dominio sin Spring y sin base de datos: un servicio con sus repositorios sustituidos por mocks de Mockito. Son los más rápidos y los que mejor localizan un error. /crear-test-unitarios los genera para una clase o un paquete del dominio:

/crear-test-unitarios PedidoService

Lo que hace: lee la clase, identifica cada comportamiento (lo que devuelve, lo que valida, lo que lanza) y escribe un test por comportamiento en backend/src/test/java, con el mismo paquete, @DisplayName en castellano que diga el caso y Mockito para las dependencias. Los ejecuta con mvn test y se para si alguno falla por un error del código, en vez de retocar el test para que pase.

Qué no prueban: controladores ni repositorios. Eso es de los tests de API.

Tests de API con REST Assured

Los tests de API prueban cada endpoint de verdad: arrancan la aplicación (@SpringBootTest en un puerto aleatorio, contra la base de datos del worktree con sus datos de prueba) y hacen peticiones HTTP con REST Assured comprobando el código de estado y el JSON. /crear-test-api los genera para una entidad:

Se llaman <Entidad>ApiIT y los ejecuta Failsafe, no Surefire. Son los dos plugins de tests de Maven: Surefire corre en la fase test los ficheros *Test (es lo que lanza mvn test); Failsafe corre en la fase integration-test los ficheros *IT, y a esa fase solo se llega con mvn verify. Está pensado para tests que necesitan algo levantado, como aquí la base de datos: así un build normal no la necesita y los de API se lanzan cuando se quiere.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-failsafe-plugin</artifactId>
  <executions>
    <execution>
      <goals><goal>integration-test</goal><goal>verify</goal></goals>
    </execution>
  </executions>
</plugin>

/crear-test-api Pedido

Por cada endpoint del controlador, un test del caso bueno y uno por cada error que el plan o las validaciones prevén: 400 con un campo obligatorio vacío, 404 con un id que no existe, 409 con un valor único repetido. Los datos de partida son los del R__ de la entidad; los tests que escriben se limpian a sí mismos (borran lo que crean) para que se puedan pasar dos veces seguidas.

@Test
@DisplayName("POST /api/pedidos sin número devuelve 400 y el nombre del campo")
void crearSinNumero() {
    given().contentType(JSON).body(Map.of("fecha", "2026-10-14", "clienteId", 1))
    .when().post("/api/pedidos")
    .then().statusCode(400).body("errores.numero", notNullValue());
}

mvn test corre unitarios y arquitectura; mvn verify corre además los de API. Son los mismos comandos para el alumno, para el agente y para CI.

Tests E2E con Playwright

Los tests E2E prueban la aplicación completa desde el navegador, como lo haría el usuario. Los criterios de aceptación del plan son frases comprobables. /crear-test-e2e las convierte en tests de Playwright en TypeScript, frontend/e2e/<entidad>.spec.ts, y los deja pasando:

/crear-test-e2e planes/12-alta-clientes.md

Cómo trabaja: lee los criterios, abre la aplicación del worktree con el Playwright MCP para ver qué hay en pantalla, escribe el test y lo ejecuta con npm run e2e; si falla por un selector o un texto, lo arregla y lo vuelve a pasar. La IA interviene al generar, no al ejecutar: lo que queda en el repositorio es un .spec.ts normal, determinista, que CI ejecuta sin ninguna IA.

Reglas que la skill tiene que respetar (están en convenciones-frontend):

  • Selectores por data-testid y por rol (getByRole, getByLabel), nunca por clase CSS. Un test que depende del CSS se rompe al primer cambio de estilo.
  • Un test por criterio de aceptación, con el criterio como nombre del test.
  • Los tests cuentan con los datos de prueba del tema 3 y se pasan sobre la base de datos recién reseteada (docker compose down -v && docker compose up -d).

Revisión por IA antes de cerrar

Sin pull request nadie mira el código antes de que llegue a develop. Lo mira la IA. /revisar compara el diff de la rama contra develop con dos cosas:

  • El plan del issue: ¿hace lo que se pidió, y como se pidió? ¿Falta algún criterio de aceptación? ¿Ha hecho cosas que no estaban en el plan?
  • Las skills de convenciones: ¿está en las capas correctas, con los nombres correctos, con migración y datos de prueba, con data-testid?

Y clasifica cada cosa que encuentra en grave (no cumple el plan, rompe una convención, falta un test) o mejorable. /git-flow finalizar lanza /revisar como primer paso y no fusiona si hay algo grave: enseña la revisión y se para. El alumno corrige (o le pide al agente que corrija) y vuelve a finalizar.

El alumno lee la revisión. El código lo ha escrito la IA, pero el commit lo firma él y es responsable de lo que hay en develop. La revisión es una ayuda para leer, no una excusa para no leer.

Un CRUD con una skill

Los CRUD de este proyecto son siempre iguales: solo cambian la entidad y sus campos. Cuando el «cómo» no cambia, no hace falta un plan cada vez; hace falta una skill que tenga el «cómo» escrito:

/crud Pedido
Campos: numero (texto, único, obligatorio), fecha (fecha, obligatoria),
cliente (relación con Cliente, obligatoria), total (decimal, >= 0).

Y genera lo mismo que tiene el CRUD de referencia: migración V<n>__pedidos.sql, entidad, repositorio, servicio, controlador y DTO en sus capas, listado y formulario en Angular con sus rutas y validaciones, R__pedidos.sql con datos de prueba y los tests unitarios, de API y E2E, llamando a las skills de este tema.

La skill se construye a partir del CRUD del tema 4: se le pide al agente que lo lea y escriba /crud con el procedimiento (qué ficheros crea, en qué orden, cómo se nombran) y con ese CRUD como ejemplo de referencia dentro de la skill, en un fichero aparte que carga cuando la ejecuta.

La lección va más allá del CRUD: lo que se repite, se convierte en una skill. Si la tercera vez que se pide algo sale distinto de las dos anteriores, es que faltaba la skill.

Ejercicios

Ejercicio 1

  • Crea un issue «Tests de arquitectura» e inícialo.
  • Escribe la skill /crear-test-arquitectura: recibe reglas en castellano y genera los tests ArchUnit en backend/src/test, cada uno con @DisplayName y comentario con qué comprueba, por qué y las excepciones.
  • Lánzala con las seis reglas del tema. mvn test tiene que pasar.
  • Mueve a mano el servicio del CRUD al paquete controller y comprueba que mvn test falla con el mensaje del test. Deshazlo.
  • Finaliza el issue.

Ejercicio 2

  • Crea un issue «Tests unitarios y de API del CRUD» e inícialo.
  • Añade al pom.xml rest-assured (Mockito viene con spring-boot-starter-test) y el plugin maven-failsafe-plugin.
  • Escribe la skill /crear-test-unitarios: recibe una clase o un paquete del dominio y genera un test JUnit 5 por comportamiento, con Mockito y sin Spring.
  • Lánzala con el servicio del CRUD del tema 4. mvn test tiene que pasar.
  • Escribe la skill /crear-test-api: recibe una entidad y genera <Entidad>ApiIT con REST Assured, un test por endpoint del caso bueno y uno por cada error previsto, sobre @SpringBootTest con la base de datos del worktree.
  • Lánzala con la entidad del CRUD. mvn test no debe ejecutarlos y mvn verify tiene que pasar dos veces seguidas.
  • Introduce un error a mano en una validación del servicio y comprueba qué tests lo detectan: tiene que caer al menos un unitario y uno de API. Deshazlo.
  • Finaliza el issue.

Ejercicio 3

  • Crea un issue «Tests E2E del CRUD» e inícialo.
  • Instala Playwright en frontend/ (npm init playwright@latest) configurado contra http://localhost:$FRONTEND_PORT y añade el script e2e al package.json (tema 3).
  • Escribe la skill /crear-test-e2e: recibe un fichero de plan, resetea la base de datos, abre la aplicación con el MCP de Playwright, escribe un .spec.ts por criterio de aceptación y lo ejecuta hasta que pase.
  • Lánzala con el plan del CRUD del tema 4. npm run e2e tiene que pasar dos veces seguidas.
  • Finaliza el issue.

Ejercicio 4

  • Crea un issue «Revisión por IA» e inícialo.
  • Escribe la skill /revisar: diff de la rama contra develop, comparación con el plan del issue y con las skills de convenciones, salida clasificada en grave / mejorable.
  • Amplía /git-flow finalizar para que lance /revisar primero y se pare si hay algo grave.
  • Finaliza el issue.

Ejercicio 5

  • Crea un issue para la segunda entidad de tu proyecto e inícialo.
  • Escribe la skill /crud a partir del CRUD del tema 4: procedimiento con los ficheros que crea y en qué orden, y el CRUD de referencia como ejemplo en un fichero aparte dentro de la skill.
  • Lánzala: /crud <Entidad> con sus campos. Comprueba que genera migración, capas, frontend, datos de prueba y los tests unitarios, de API y E2E, y que mvn verify y npm run e2e pasan.
  • Quita a mano del plan un criterio de aceptación sin quitar su código y lanza /git-flow finalizar. /revisar tiene que marcarlo como grave y la fusión no debe hacerse. Restaura el plan y finaliza.
clase/daw/daw-proyecto/tema05.1791931187.txt.gz · Última modificación: por claude