← Back to Blog

Los tests unitarios como salvaguarda frente a cambios no deseados

Los tests unitarios como salvaguarda frente a cambios no deseados

Esperamos que los tests unitarios verifiquen la corrección de la lógica modificada y ayuden a detectar cambios no deseados en el comportamiento de la aplicación. Al desarrollar con IA, también es esencial comprobar que la funcionalidad fuera del alcance de la tarea sigue intacta.

Verificar que una nueva funcionalidad funciona es, por tanto, solo una parte del trabajo. También tenemos que comprobar que el cambio no ha roto las reglas existentes de la aplicación.

Qué deben proteger los tests unitarios

Los tests unitarios verifican el comportamiento de partes individuales del código. También actúan como salvaguarda frente a regresiones, es decir, errores introducidos al cambiar un comportamiento que antes funcionaba.

Esta protección es especialmente valiosa para el código generado por IA. La IA puede cumplir un requisito concreto y, al mismo tiempo, modificar lógica que debía permanecer intacta.

Unos tests bien diseñados ayudan a definir los límites de un cambio:

Este es el comportamiento que queremos cambiar. Estas reglas deben seguir cumpliéndose.

Probar según el riesgo y las dependencias reales

No necesitamos escribir automáticamente un test aparte para cada getter, setter o clase de datos simple.

Un test que se limita a repetir la implementación puede aumentar el número de tests sin aportar mucho valor. Además, genera más trabajo de mantenimiento cuando se hacen nuevos cambios.

Una regla práctica es:

Para un cambio concreto, céntrate en el comportamiento modificado y en las partes de la aplicación que dependen de él. Determina el alcance de las pruebas según el impacto potencial.

Para métodos simples sin lógica de decisión, un test unitario aparte puede ser innecesario si otros tests cubren adecuadamente su comportamiento.

Sin embargo, la simplicidad por sí sola no es motivo para asumir que la IA no se equivocará. Incluso un método de una sola línea puede determinar el precio de un pedido o los derechos de acceso de un usuario.

Antes de añadir un test, hazte tres preguntas:

  1. ¿Qué comportamiento cambia en esta Task?

Verificamos que el cambio cumple los requisitos.

  1. ¿Qué reglas y componentes dependientes deben permanecer intactos?

Buscamos los lugares donde el cambio podría causar una regresión.

  1. ¿Detectará el test un error real?

Verificamos el comportamiento esperado en lugar de limitarnos a copiar la implementación.

Los tests deben conectarse con la lógica de negocio

Los tests unitarios más valiosos protegen reglas concretas de la aplicación.

Para un método de cálculo de descuentos, por ejemplo, no basta con comprobar que devuelve un número. Necesitamos saber si siguen cumpliéndose estas reglas:

  • el descuento no supera el límite permitido;

  • el precio final no cae por debajo de cero;

  • un cliente que no tiene derecho a descuento paga el precio completo;

  • el cálculo sigue las reglas de redondeo definidas.

La conexión entre un método y una regla de negocio es lo que da sentido a un test.

La implementación puede cambiar. Una regla fuera del alcance previsto de la Task debe permanecer intacta.

Cómo lo aborda AITM

AITM conecta el desarrollo con IA con el contexto del proyecto, los contratos y las dependencias entre las distintas partes de la aplicación.

Antes de la implementación, el arquitecto identifica qué debe cambiar, cómo están conectadas las partes relevantes y qué reglas deben permanecer intactas. El paso de testing utiliza después esta información.

Por tanto, la pregunta clave es más que si la IA sabe escribir un test. Es si la IA sabe qué debe proteger el test y por qué.

Considera un cambio en DiscountService.calculateDiscount(). Si el contrato usa dependsOnModules para registrar que OrderSummary.render() también depende del cálculo del descuento, el paso de testing tiene motivos para comprobar también el impacto en el resumen del pedido.

El cálculo en sí puede comprobarse con un test unitario. Un test de integración puede ser más adecuado para comprobar cómo funciona el cálculo junto con el resumen del pedido.

Los tests se diseñan, por tanto, en torno a las dependencias y los riesgos reales del cambio concreto.

Diez tests para una Task, dos mil para otra

No todas las Tasks necesitan el mismo alcance de pruebas.

A modo de ilustración, en un proyecto con 32 467 tests, un cambio pequeño puede requerir ejecutar diez tests relevantes. Un cambio en lógica de negocio compartida puede requerir dos mil.

El propósito de las pruebas dirigidas es seleccionar los tests que cubren el comportamiento modificado y sus dependencias. Esto puede acortar el ciclo de feedback y centrar la verificación en los riesgos de la Task.

Las comprobaciones de regresión más amplias o una suite de tests completa siguen teniendo su lugar para cambios extensos o antes de una nueva versión.

El número de tests ejecutados debe reflejar el impacto del cambio.

Cuando un test falla, necesitamos entender por qué

Un test que falla no siempre indica el mismo problema. Tenemos que distinguir entre estas situaciones:

  • se introdujo un error en la implementación;

  • el cambio violó sin querer una regla de negocio existente;

  • una nueva funcionalidad cambió intencionadamente el comportamiento esperado y hay que actualizar el test.

Los requisitos de la Task, los contratos y las descripciones de lógica de negocio proporcionan el contexto para esta evaluación.

Si un requisito ha cambiado legítimamente, el test correspondiente también debe cambiar. Si la IA ha violado una regla que debía permanecer intacta, hay que corregir la implementación.

Simplemente modificar un test para que vuelva a pasar podría ocultar un error real.

Los tests unitarios son la primera capa de protección

Cada nivel de pruebas tiene un papel distinto:

  • Los tests unitarios verifican partes individuales de la lógica.

  • Los tests de integración verifican cómo funcionan juntos los módulos y los sistemas.

  • Los tests E2E comprueban recorridos completos del usuario en una aplicación en ejecución.

Estas capas se complementan. Cada una detecta distintos tipos de errores y ayuda a verificar un cambio desde una perspectiva diferente.

Al desarrollar con IA, comprobamos por tanto dos cosas: si la Task se completó y si el comportamiento fuera de su alcance previsto permaneció intacto.

Conectar los requisitos de la Task, la lógica de negocio, las dependencias y los tests es una parte importante de la orquestación de AITM.

Los tests unitarios como salvaguarda frente a cambios no deseados — captura 1

P. ej., tests unitarios

Más información en https://www.aitm.cz

#AITM #UnitTesting #SoftwareTesting #AI #SoftwareDevelopment