====== 04 - Introducción a las pruebas ====== Una **prueba** es un fragmento de código que compara el comportamiento real de la aplicación con el comportamiento esperado. Las pruebas automáticas se ejecutan sin intervención humana y permiten cambiar el código con confianza. ===== 1. Para qué sirven ===== * **Fiabilidad:** detectan errores antes de llegar a producción. * **Red de seguridad:** permiten refactorizar y añadir funcionalidad sin romper lo existente (**regresión**). * **Documentación ejecutable:** los casos de prueba muestran cómo se usa el código. * **Mejor diseño:** el código difícil de probar suele tener acoplamiento; probarlo empuja a separar responsabilidades. Una prueba que se ejecuta y pasa no garantiza la ausencia de errores; garantiza que **el comportamiento probado** funciona. ===== 2. Manual y automática ===== ^ Tipo ^ Cómo se ejecuta ^ Cuándo ^ | **Manual** | Una persona interactúa con la aplicación | Exploración, comprobación puntual | | **Automática** | El propio código de prueba se ejecuta en cada build | Regresión, validación continua | Las automáticas son la base del desarrollo moderno: se ejecutan miles de veces, en cada cambio, de forma idéntica. ===== 3. Tipos de pruebas ===== ^ Tipo ^ Qué comprueba ^ Ejemplo ^ | **Unitarias** | Una unidad de código aislada (clase, método) | Que un método calcula el total con descuento | | **Integración** | Que varias piezas colaboran correctamente | Que el service consulta el repository y devuelve el dato | | **Arquitectura** | Que el código respeta las reglas estructurales | Que la capa controller no depende de persistence | | **E2E** | El sistema completo, desde la interfaz, como un usuario | Registrar un usuario y ver su perfil en la aplicación real | ===== 4. La pirámide de pruebas ===== @startuml !theme cerulean skinparam backgroundColor transparent skinparam shadowing false skinparam ArrowThickness 1 skinparam classAttributeIconSize 0 skinparam class { BackgroundColor #FEFEFE BorderColor #344883 ArrowColor #344883 FontColor #343A40 } skinparam classAttributeFontColor #343A40 skinparam stereotypeCBackgroundColor #344883 skinparam stereotypeCBorderColor #273768 skinparam package { BackgroundColor transparent BorderColor #344883 FontColor #343A40 } skinparam package { BackgroundColor transparent BorderColor #344883 FontColor #343A40 } skinparam ArrowColor #344883 skinparam participant { BackgroundColor #FEFEFE BorderColor #344883 FontColor #343A40 } skinparam actor { BackgroundColor #FEFEFE BorderColor #344883 FontColor #343A40 } skinparam sequence { ArrowColor #344883 LifeLineBorderColor #94A3B8 GroupBorderColor #344883 GroupBackgroundColor #E9EDF7 } skinparam note { BackgroundColor #FEF9C3 BorderColor #B6C2DE FontColor #343A40 } skinparam activity { BackgroundColor #FEFEFE BorderColor #344883 FontColor #343A40 StartColor #344883 EndColor #344883 DiamondBackgroundColor #FEFEFE DiamondBorderColor #344883 DiamondFontColor #343A40 } skinparam component { BackgroundColor #FEFEFE BorderColor #344883 FontColor #343A40 } skinparam database { BackgroundColor #FEFEFE BorderColor #344883 FontColor #343A40 } skinparam node { BackgroundColor #FEFEFE BorderColor #344883 FontColor #343A40 } skinparam cloud { BackgroundColor transparent BorderColor #344883 FontColor #344883 } skinparam rectangle { BackgroundColor #FEFEFE BorderColor #344883 FontColor #343A40 } skinparam state { BackgroundColor #FEFEFE BorderColor #344883 FontColor #343A40 } skinparam usecase { BackgroundColor #FEFEFE BorderColor #344883 FontColor #343A40 } rectangle "E2E\n(pocas, lentas)" as e2e rectangle "Integración\n(algunas)" as int rectangle "Unitarias\n(muchas, rápidas)" as unit unit -[hidden]- int int -[hidden]- e2e @enduml ^ Nivel ^ Cantidad ^ Velocidad ^ Coste ^ | **Unitarias** | Muchas | Milisegundos | Bajo | | **Integración** | Menos | Segundos | Medio | | **E2E** | Pocas | Minutos | Alto | Cuanto más alto el nivel, más realista pero más lento y frágil. Por eso la base de la pirámide es ancha: la mayor parte del comportamiento se protege con unitarias rápidas, y los E2E cubren solo los flujos críticos. ===== 5. Una buena prueba ===== * **Determinista:** siempre produce el mismo resultado con las mismas entradas. * **Aislada:** no depende del orden de ejecución ni del estado de otras pruebas. * **Focada:** comprueba un comportamiento; si falla, el fallo indica dónde mirar. * **Rápida:** para poder ejecutarla con frecuencia. Las pruebas son código: se leen, se mantienen y se refactorizan como el resto. Una prueba lenta, aleatoria o acoplada al entorno deja de usarse, y deja de proteger.