DEV Community

Cover image for Camino a CI/CD pruebas (Testing)
Johan Garcia
Johan Garcia

Posted on

Camino a CI/CD pruebas (Testing)

El stage de testing es, en la mayoría de pipelines, la etapa que sigue después de la compilación o build. En este punto, el sistema ya es ejecutable, pero aún no es confiable.

Aquí es donde entra el testing: no como un paso opcional, sino como el filtro que evita que errores, regresiones o comportamientos inesperados lleguen a producción.

En esta sección, se busca responder una pregunta clave:

¿Qué debería tener un pipeline a nivel de testing para considerarse realmente sólido?


Tipos de Testing

1. Testing Funcional

El testing funcional valida que el sistema haga lo que se espera que haga. Es decir, se enfoca en el comportamiento, no en cómo está implementado.

Unit Testing (Pruebas Unitarias)

Las pruebas unitarias validan las piezas más pequeñas del sistema: funciones, métodos o componentes individuales.

Su objetivo es detectar errores lo más temprano posible, antes de que escalen.

Qué cubren normalmente:

  • Lógica de negocio aislada
  • Validaciones
  • Transformaciones de datos
  • Casos borde

Aquí no importa el sistema completo, solo que esa unidad funcione correctamente.

Integration Testing (Pruebas de Integración)

Aquí se sube un nivel: ya no se prueba una pieza aislada, sino cómo interactúan varias partes del sistema.

El objetivo es validar que los componentes colaboren correctamente.

Qué suele incluir:

  • Componentes + servicios
  • Acceso a base de datos
  • APIs simuladas (MSW, mocks controlados)

Ejemplo conceptual:

Un componente llama a un servicio → el servicio consulta datos → el resultado se renderiza correctamente.

Si alguna de esas piezas falla en conjunto, el test lo detecta.

End-to-End Testing (E2E)

Las pruebas E2E validan el sistema completo desde la perspectiva del usuario.

Simulan flujos reales en un entorno lo más cercano posible a producción.

Ejemplo típico:

  • El usuario entra a la app
  • Hace login
  • Crea un registro
  • Lo visualiza en pantalla

Si todo eso funciona, el sistema cumple su propósito en ese flujo.

Smoke Testing

El smoke testing responde una única pregunta:

¿El sistema funciona lo suficiente como para seguir probándolo?

Se ejecuta justo después del build, y actúa como un primer filtro.

Si falla aquí, no tiene sentido continuar.

Ejemplo:

  • ¿La app levanta?
  • ¿El login responde?
  • ¿una ruta principal carga?

No valida lógica profunda ni reglas complejas.

Solo verifica lo esencial.

Este test no valida:

  • expiración del token

  • roles

  • seguridad avanzada

Solo valida algo clave: “¿el login funciona?”, Si esto falla, todo lo demás deja de tener sentido.

Sanity Testing

El sanity testing es un chequeo rápido y enfocado después de un cambio puntual.

No busca validar todo el sistema, sino algo muy concreto:

¿Lo que se modificó sigue funcionando sin romper lo demás?

Se usa cuando:

  • Hay un bug fix
  • Se hace un refactor pequeño
  • Se ajusta una funcionalidad específica

Características:

  • Dirigido (no exploratorio)
  • Ligero (no exhaustivo)
  • Rápido (busca confianza inmediata)

Regression Testing

El regression testing protege el sistema a medida que evoluciona.

Cada cambio introduce riesgo, y este tipo de pruebas actúa como una red de seguridad.

Valida que:

Lo que funcionaba → siga funcionando
Los cambios → no generen efectos colaterales

No se enfoca en lo nuevo, sino en evitar que lo existente se rompa.

User Acceptance Testing (UAT)

Es la fase donde el sistema deja de evaluarse como “código que funciona” y pasa a validarse como “producto que resuelve un problema real”. Aquí ya no importa tanto si la lógica interna está bien implementada, sino si lo que se construyó realmente cumple con lo que el usuario o el negocio esperaba.

En otras palabras, es el momento en el que alguien del lado del negocio no necesariamente un desarrollador usa la aplicación en escenarios reales y responde una pregunta clave: ¿esto sirve para lo que se necesitaba?

A diferencia de otros tipos de testing:

  • No se centra en funciones aisladas.

  • No valida detalles técnicos.

  • No busca bugs “técnicos” principalmente.

Se enfoca en algo mucho más importante:

Validar que el sistema cumple con los requisitos funcionales desde la perspectiva del usuario final.

Ejemplo

Contexto: Un módulo de inventario.

Requisito de negocio:
“El usuario debe poder registrar un producto y verlo reflejado en el inventario.”

UAT:
Escenario:

  • El usuario crea un producto: Nombre: “Laptop” Cantidad: 5
  • Guarda el registro
  • Va al listado de inventario

Resultado esperado:

  • El producto aparece
  • La cantidad es correcta

No hay inconsistencias

Si eso pasa, el sistema cumple el requisito, aunque internamente pueda tener mejoras técnicas pendientes.

Tipos de UAT que suelen aparecer
Aunque muchas veces se agrupan como uno solo, en la práctica se ven variantes:

  • Alpha Testing → interno (equipo del producto)
  • Beta Testing → usuarios reales
  • Business UAT → validación contra requisitos del negocio
  • Operational UAT → validación en condiciones reales (ambiente, datos, etc.)

Consideraciones

El UAT no lo hace el desarrollador

Normalmente lo ejecutan:

  • Stakeholders

  • QA con enfoque de negocio

  • Cliente final

Porque lo que se valida no es el código, sino la utilidad real del sistema.

Su finalidad es

  • Ejecutarse en entornos de staging

  • Ser parcialmente manual (aunque puede automatizarse con criterios de aceptación)

  • Actuar como último gate antes de producción

Contract Testing

Este tipo de testing se vuelve crítico en arquitecturas distribuidas.

Valida que dos sistemas que se comunican (por ejemplo, frontend y backend) respeten un contrato.

Ese contrato define:

  • Request
  • Response
  • Tipos de datos
  • Campos obligatorios

Problema típico que resuelve:

  • El backend funciona, sus tests pasan… pero el frontend se rompe.

  • El contract testing evita ese tipo de desalineaciones.

  • El backend funciona

  • Los tests del backend pasan

  • Pero el frontend se rompe

Aquí es donde el Contract Testing evita el desastre.

Tipos de Contract Testing
Consumer-Driven Contract Testing (el más usado)
El consumidor (frontend) define lo que necesita.

Ejemplo

Provider Verification
El backend valida que cumple ese contrato.

Ejemplo


2. Testing No Funcional
Aquí no se valida qué hace el sistema, sino cómo se comporta.

Performance Testing
Se centra en evaluar cómo se comporta una aplicación bajo distintas condiciones de carga, no desde la lógica funcional, sino desde atributos como tiempo de respuesta, throughput, uso de recursos y estabilidad. En términos prácticos, lo que se busca es responder preguntas como: ¿cuántos usuarios simultáneos puede soportar el sistema?, ¿qué tan rápido responde bajo presión?, ¿en qué punto comienza a degradarse? Este tipo de pruebas es clave en sistemas reales porque muchos fallos no aparecen en desarrollo, sino cuando el sistema enfrenta tráfico real. Dentro de este enfoque se incluyen variantes como load testing, stress testing y spike testing, cada una orientada a distintos patrones de carga.

Ejemplo

El el ejemplo anterior se simulan 50 usuarios concurrentes durante 30 segundos haciendo peticiones al mismo endpoint. Si el sistema responde rápido y sin errores, el comportamiento es aceptable. Si el tiempo de respuesta aumenta significativamente o aparecen errores (timeouts, 500), entonces ya se está evidenciando un problema de rendimiento.

Security Testing
Aunque forma parte del testing, muchas veces se maneja como un stage independiente.

Incluye:

  • SAST - Static Application Security Testing (análisis estático)

  • DAST - Dynamic Application Security Testing (análisis dinámico)

  • SCA - Software Composition Analysis

  • Secrets Detection

  • Container Security

  • IaC, API, y Compliance

  • Security Headers

  • Dependency Scanning

Mutation Testing (Pruebas de Mutación)
El mutation testing pregunta: "Si introduzco un pequeño bug en mi código, ¿mis pruebas realmente lo detectarán?" Esto revela la diferencia crítica entre cobertura de pruebas y efectividad de pruebas.

El resultado se mide con el mutation score.

Ejemplo

Herramientas

Testing Unitario e Integración

  • Jest (JavaScript/TypeScript)
  • Pytest (Python):
  • JUnit (Java)
  • NUnit (C#/.NET)

Testing E2E y UI

  • Selenium: Arquitectura empresarial de Selenium Python con Pytest, Allure y patrones de diseño GitHub
  • Cypress
  • Playwright
  • Puppeteer

Contract Testing

  • Pact: Flujo típico con Pact:

    • El frontend define el contrato
    • Se guarda como archivo (.json)
    • El backend ejecuta tests contra ese contrato Si algo no coincide → falla el pipeline

Testing Performance

  • Locust (Python)
  • K6 (JavaScript/TS): Ofrece integración nativa con CI/CD y la nube.
  • Gatling (Java/Kotlin/JS/Scala)
  • Apache JMeter Java/GUI): Ideal para equipos QA tradicionales y empresas, siendo opensource.
  • Atillery (Node.js/YAML)
  • Vegeta (Go)

Alternativas en la nube para Testing performance

  • BlazeMeter: Permite ejecutar scripts de JMeter, k6, Locust y Gatling en la nube
  • LoadNinja: Se enfoca en pruebas con navegadores reales en lugar de simular protocolos, lo que da métricas de experiencia de usuario más precisas. No requiere programación
  • Azure Load Testing: Un servicio gestionado por Microsoft que permite subir scripts de JMeter y ofrece integraciones profundas con el ecosistema de Azure.
  • OctoPerf: Diseñado específicamente para usuarios de JMeter que quieren una interfaz web moderna

Testing Mutation

  • PIT (PITest) para Java con escalabilidad empresarial.
  • Stryker Mutator con soporte multi-lenguaje (JavaScript, TypeScript, C#, Scala).
  • MutPy para Python.
  • Infection para PHP.

Un buen stage de testing no se define por la cantidad de herramientas o tests, sino por su capacidad de generar confianza.

Al final, todo se resume en esto:

Detectar errores lo antes posible, con el menor costo posible, y antes de que impacten al usuario.

Si el pipeline logra eso, entonces está bien diseñado.

Top comments (0)