El testing de software se organiza en niveles distintos, cada uno dirigido a diferentes aspectos del sistema e involucrando a diferentes miembros del equipo. Comprender los niveles de testing ayuda a los equipos a estructurar su estrategia de testing, asignar responsabilidades y garantizar una cobertura de calidad integral desde componentes individuales hasta sistemas completos.

¿Qué Son los Niveles de Testing?

Los niveles de testing representan etapas en el ciclo de vida de desarrollo de software donde ocurren actividades de testing. Cada nivel tiene objetivos específicos, base de pruebas, objetos de prueba y defectos típicos para encontrar.

Los Cuatro Niveles Principales de Testing

┌─────────────────────────────────────────────┐
│    User Acceptance Testing (UAT)            │ ← Negocio valida requisitos
├─────────────────────────────────────────────┤
│            System Testing                   │ ← Comportamiento del sistema completo
├─────────────────────────────────────────────┤
│         Integration Testing                 │ ← Interacciones entre componentes
├─────────────────────────────────────────────┤
│            Unit Testing                     │ ← Componentes individuales
└─────────────────────────────────────────────┘

Cada nivel se construye sobre el anterior, con defectos idealmente detectados en la etapa más temprana posible para minimizar costo y complejidad. Para una comprensión profunda de los diferentes enfoques de testing a través de estos niveles, consulta nuestra comparación de enfoques de testing.

Unit Testing

El unit testing verifica componentes individuales (funciones, métodos, clases) de forma aislada. Esta es la base de la pirámide de testing.

Objetivos

  • Verificar que cada unidad funciona según diseño
  • Detectar errores de lógica temprano en desarrollo
  • Habilitar refactoring seguro mediante detección de regresiones
  • Documentar comportamiento esperado de unidades de código
  • Proporcionar feedback rápido a desarrolladores

Base de Pruebas

  • Documentos de diseño detallado
  • Implementación de código
  • Especificaciones de componentes
  • Documentación de API

¿Quién Realiza Unit Testing?

Principalmente desarrolladores, a menudo usando Test-Driven Development (TDD):

# Ejemplo: Unit test para servicio de autenticación
import pytest
from auth_service import AuthService, InvalidCredentialsError

class TestAuthService:
    def setup_method(self):
        """Configurar fixtures antes de cada test"""
        self.auth = AuthService(database="test_db")
 (como se discute en [Entry and Exit Criteria in Software Testing: When to Start and Stop Testing](/blog/entry-exit-criteria))        self.valid_user = {
            "email": "test@example.com",
            "password": "SecurePass123!"
        }

    def test_successful_authentication(self):
        """Test de que credenciales válidas retornan auth token"""
        token = self.auth.authenticate(
            self.valid_user["email"],
            self.valid_user["password"]
        )

        assert token is not None
        assert len(token) == 64  # Longitud de JWT token
        assert self.auth.is_token_valid(token) is True

    def test_invalid_password_raises_error(self):
        """Test de que contraseña inválida genera error apropiado"""
        with pytest.raises(InvalidCredentialsError) as exc_info:
            self.auth.authenticate(
                self.valid_user["email"],
                "WrongPassword"
            )

        assert "Invalid credentials" in str(exc_info.value)

    def test_nonexistent_user_raises_error(self):
        """Test de que usuario no existente genera error"""
        with pytest.raises(InvalidCredentialsError):
            self.auth.authenticate(
                "nonexistent@example.com",
                "anypassword"
            )

    def test_account_lockout_after_failed_attempts(self):
        """Test de que cuenta se bloquea después de 5 intentos fallidos"""
        # Intentar 5 logins fallidos
        for _ in range(5):
            with pytest.raises(InvalidCredentialsError):
                self.auth.authenticate(
                    self.valid_user["email"],
                    "WrongPassword"
                )

        # 6to intento debe generar AccountLockedError
        from auth_service import AccountLockedError
        with pytest.raises(AccountLockedError):
            self.auth.authenticate(
                self.valid_user["email"],
                self.valid_user["password"]  # Incluso con contraseña correcta
            )

    def test_token_expiration(self):
        """Test de que tokens expiran después de tiempo configurado"""
        import time

        token = self.auth.authenticate(
            self.valid_user["email"],
            self.valid_user["password"]
        )

        # Simular paso de tiempo (en código real, usar librería de time mocking)
        self.auth._set_time_offset(3600)  # +1 hora

        assert self.auth.is_token_valid(token) is False

Defectos Típicos Encontrados

  • Cálculos o lógica incorrecta
  • Errores de valores límite
  • Excepciones de puntero nulo
  • Tipos de variable incorrectos
  • Errores de bucle (off-by-one, bucles infinitos)
  • Manejo de errores incorrecto

Mejores Prácticas

  1. Seguir patrón AAA: Arrange, Act, Assert
  2. Probar una cosa por test: Cada test debe verificar un comportamiento único
  3. Usar nombres descriptivos: test_account_locks_after_5_failed_attempts
  4. Aislar dependencias: Usar mocks/stubs para dependencias externas
  5. Apuntar a alta cobertura: Mínimo 70-80%, código crítico 100%
  6. Ejecución rápida: Unit tests deben ejecutarse en milisegundos

Integration Testing

El (como se discute en Dynamic Testing: Testing in Action) integration testing verifica interacciones entre componentes o sistemas integrados. Detecta defectos de interfaz que los unit tests omiten.

Objetivos

  • Verificar interfaces entre componentes
  • Probar flujo de datos entre módulos
  • Validar contratos de API
  • Detectar bugs de integración temprano
  • Probar escenarios de interacción de componentes

Base de Pruebas

  • Documentos de diseño de software y sistema
  • Diagramas de arquitectura
  • Especificaciones de API
  • Definiciones de interfaz
  • Descripciones de casos de uso

Enfoques de Integración

Integración Big Bang:

Todos los componentes integrados simultáneamente → Probar todo de una vez

Pros: Rápido de configurar
Contras: Difícil aislar defectos, arriesgado

Integración Incremental:

Componentes integrados y probados incrementalmente

Top-Down: Comenzar con módulos de alto nivel, stub niveles inferiores
Bottom-Up: Comenzar con módulos de bajo nivel, crear drivers para niveles superiores
Sandwich: Combinación de top-down y bottom-up

Ejemplo: API Integration Testing

// Ejemplo: Testing de integración entre autenticación y servicio de usuario
const request = require('supertest');
const app = require('../app');

describe('Integración de Autenticación y Servicio de Usuario', () => {
  let authToken;
  let userId;

  beforeAll(async () => {
    // Configurar base de datos de prueba
    await setupTestDatabase() (como se discute en [Grey Box Testing: Best of Both Worlds](/blog/grey-box-testing));
  });

  afterAll(async () => {
    // Limpiar base de datos de prueba
    await cleanupTestDatabase();
  });

  test('Registro de usuario crea usuario y retorna auth token', async () => {
    const newUser = {
      email: 'integration@test.com',
      password: 'SecurePass123!',
      name: 'Integration Test User'
    };

    const response = await request(app)
      .post('/api/auth/register')
      .send(newUser)
      .expect(201);

    // Verificar estructura de respuesta
    expect(response.body).toHaveProperty('token');
    expect(response.body).toHaveProperty('user');
    expect(response.body.user.email).toBe(newUser.email);

    // Guardar para tests subsecuentes
    authToken = response.body.token;
    userId = response.body.user.id;
  });

  test('Usuario autenticado puede acceder endpoint de perfil', async () => {
    const response = await request(app)
      .get(`/api/users/${userId}/profile`)
      .set('Authorization', `Bearer ${authToken}`)
      .expect(200);

    expect(response.body.email).toBe('integration@test.com');
    expect(response.body.name).toBe('Integration Test User');
  });

  test('Solicitud no autenticada a perfil retorna 401', async () => {
    await request(app)
      .get(`/api/users/${userId}/profile`)
      .expect(401);
  });

  test('Token inválido retorna 403', async () => {
    await request(app)
      .get(`/api/users/${userId}/profile`)
      .set('Authorization', 'Bearer invalid_token_here')
      .expect(403);
  });

  test('Usuario puede actualizar perfil con auth token válido', async () => {
    const updates = {
      name: 'Updated Name',
      bio: 'Integration testing is awesome'
    };

    const response = await request(app)
      .patch(`/api/users/${userId}/profile`)
      .set('Authorization', `Bearer ${authToken}`)
      .send(updates)
      .expect(200);

    expect(response.body.name).toBe('Updated Name');
    expect(response.body.bio).toBe('Integration testing is awesome');
  });

  test('Logout invalida auth token', async () => {
    // Logout
    await request(app)
      .post('/api/auth/logout')
      .set('Authorization', `Bearer ${authToken}`)
      .expect(200);

    // Intentar acceder a perfil con token invalidado
    await request(app)
      .get(`/api/users/${userId}/profile`)
      .set('Authorization', `Bearer ${authToken}`)
      .expect(401);
  });
});

Defectos Típicos Encontrados

  • Parámetros incorrectos de llamadas API
  • Desajustes de formato de datos entre componentes
  • Manejo de errores faltante o incorrecto entre servicios
  • Problemas de timing (condiciones de carrera, deadlocks)
  • Suposiciones incorrectas sobre comportamiento de componentes
  • Problemas de conexión a base de datos
  • Fallos de comunicación de cola de mensajes

Mejores Prácticas

  1. Probar escenarios realistas: Usar flujos de integración reales
  2. Usar bases de datos de prueba: Aislar de datos de producción
  3. Probar condiciones de error: Fallos de red, timeouts, respuestas inválidas
  4. Mantener datos de prueba: Crear fixtures reutilizables
  5. Ejecutar en CI/CD: Automatizar ejecución en cada build
  6. Contract testing: Verificar contratos API entre servicios

System Testing

El system testing valida el sistema completo e integrado contra requisitos especificados. Prueba escenarios end-to-end desde perspectiva de usuario.

Objetivos

  • Verificar que sistema cumple requisitos funcionales
  • Validar comportamiento del sistema en entornos realistas
  • Probar requisitos no funcionales (performance, seguridad, usabilidad)
  • Verificar integración apropiada del sistema con sistemas externos
  • Validar flujos de trabajo completos de usuario

Base de Pruebas

  • Especificaciones de requisitos de sistema y software
  • Casos de uso y user stories
  • Documentos de arquitectura del sistema
  • Descripciones de procesos de negocio
  • Documentación de usuario

¿Quién Realiza System Testing?

Equipo de testing independiente o ingenieros de QA, separados del equipo de desarrollo para asegurar objetividad.

Tipos de System Testing

TipoEnfoqueEjemplo
FuncionalFuncionalidades trabajan según especificadoProceso de checkout e-commerce
PerformanceTiempos de respuesta, throughputCargar 1000 usuarios concurrentes
SeguridadVulnerabilidades, control de accesoAtaques SQL injection, XSS
UsabilidadExperiencia de usuario, facilidad de usoNavegación, validación de formularios
CompatibilidadFunciona en diferentes entornosCross-browser, dispositivos móviles
RecuperaciónSistema se recupera de fallosRecuperación de caída de BD
InstalaciónDeployment y configuraciónInstalación limpia, escenarios de upgrade

Ejemplo: Escenarios de System Test

# System Test Funcional: Flujo de Compra E-commerce

Feature: Flujo completo de compra
  Como cliente
  Quiero comprar productos
  Para que pueda recibirlos en mi dirección

Background:
  Given el sistema e-commerce está funcionando
  And existen productos de prueba en inventario
  And existe cuenta de usuario de prueba "systemtest@example.com"

Scenario: Compra exitosa de producto con tarjeta de crédito
  Given estoy autenticado como "systemtest@example.com"
  When busco "wireless headphones"
  And selecciono "Sony WH-1000XM4" de resultados
  And hago clic en "Agregar al Carrito"
  And procedo al checkout
  And ingreso dirección de envío:
    | Campo      | Valor              |
    | Calle      | 123 Test St        |
    | Ciudad     | San Francisco      |
    | Estado     | CA                 |
    | Código     | 94105              |
  And selecciono "Tarjeta de Crédito" como método de pago
  And ingreso detalles válidos de tarjeta de crédito
  And confirmo la orden
  Then debo ver mensaje "Orden Confirmada"
  And debo recibir email de confirmación de orden en menos de 2 minutos
  And el estado de orden debe ser "Procesando" en mi cuenta
  And el inventario debe decrementarse por 1 para "Sony WH-1000XM4"
  And el pago debe procesarse por $349.99

Scenario: Manejo de producto sin stock
  Given producto "Limited Edition Watch" tiene 0 inventario
  When intento agregarlo al carrito
  Then debo ver notificación "Fuera de Stock"
  And botón "Agregar al Carrito" debe estar deshabilitado
  And debo ver opción "Notificarme cuando esté disponible"

Scenario: Información de pago inválida
  Given tengo artículos en mi carrito
  When procedo al checkout
  And ingreso número de tarjeta de crédito inválido "1234 5678 9012 3456"
  And confirmo la orden
  Then debo ver error "Información de pago inválida"
  And orden no debe crearse
  And inventario no debe decrementarse

Ejemplo de Performance Testing

# Ejemplo: Load testing para validación de performance del sistema
from locust import HttpUser, task, between

class EcommerceUser(HttpUser):
    wait_time = between(1, 3)  # Esperar 1-3 segundos entre requests

    def on_start(self):
        """Login cuando usuario inicia"""
        response = self.client.post("/api/auth/login", json={
            "email": "loadtest@example.com",
            "password": "TestPass123!"
        })
        self.token = response.json()["token"]

    @task(3)
    def browse_products(self):
        """Navegar productos (alta frecuencia)"""
        self.client.get("/api/products", headers={
            "Authorization": f"Bearer {self.token}"
        })

    @task(2)
    def view_product_detail(self):
        """Ver producto específico (frecuencia media)"""
        self.client.get("/api/products/12345", headers={
            "Authorization": f"Bearer {self.token}"
        })

    @task(1)
    def add_to_cart(self):
        """Agregar producto al carrito (menor frecuencia)"""
        self.client.post("/api/cart/items", json={
            "productId": "12345",
            "quantity": 1
        }, headers={
            "Authorization": f"Bearer {self.token}"
        })

    @task(1)
    def view_cart(self):
        """Ver carrito de compras"""
        self.client.get("/api/cart", headers={
            "Authorization": f"Bearer {self.token}"
        })

# Ejecutar con: locust -f system_load_test.py --users 1000 --spawn-rate 50
# Prueba sistema con 1000 usuarios concurrentes, aumentando 50 usuarios por segundo

Defectos Típicos Encontrados

  • Requisitos funcionales no cumplidos
  • Errores de lógica de negocio
  • Fallos de workflow end-to-end
  • Cuellos de botella de performance
  • Vulnerabilidades de seguridad
  • Problemas de compatibilidad entre browsers/dispositivos
  • Mensajes de error o manejo incorrecto
  • Problemas de integridad de datos

Mejores Prácticas

  1. Probar en entorno similar a producción: Igualar arquitectura, volúmenes de datos
  2. Usar datos de prueba realistas: Representar patrones de uso real
  3. Automatizar tests de regresión: Funcionalidad core debe estar automatizada
  4. Probar requisitos no funcionales: Performance, seguridad, escalabilidad
  5. Documentar resultados de pruebas: Reporting comprensivo para stakeholders
  6. Priorizar por riesgo: Enfocarse primero en flujos críticos de negocio

User Acceptance Testing (UAT)

UAT valida que el sistema cumple requisitos de negocio y está listo para deployment. Usuarios reales prueban en escenarios realistas.

Objetivos

  • Verificar que sistema cumple necesidades de negocio
  • Validar usabilidad desde perspectiva de usuario final
  • Asegurar que sistema está listo para deployment a producción
  • Ganar confianza de stakeholders
  • Identificar brechas entre requisitos e implementación

Base de Pruebas

  • Requisitos y procesos de negocio
  • Requisitos de usuario y user stories
  • Manuales de usuario y materiales de training
  • Flujos de trabajo de procesos de negocio
  • Criterios de aceptación

¿Quién Realiza UAT?

Usuarios de negocio, product owners, stakeholders—las personas que realmente usarán el sistema.

Tipos de UAT

Alpha Testing:

  • Realizado por personal interno (no equipo de desarrollo)
  • Conducido en entorno de desarrollo
  • Feedback temprano antes de usuarios externos

Beta Testing:

  • Realizado por usuarios finales reales
  • Conducido en producción o entorno cercano a producción
  • Escenarios de uso del mundo real
  • Feedback recolectado para mejoras finales

Contract Acceptance Testing:

  • Valida que sistema cumple especificaciones de contrato
  • A menudo legalmente vinculante
  • Realizado antes de pago/entrega

Operational Acceptance Testing:

  • Valida preparación del sistema para operación
  • Prueba backup/recuperación, mantenibilidad, seguridad
  • A menudo realizado por equipo de operaciones

Ejemplo: UAT Test Case

## UAT Test Case: Generación de Reporte Financiero Mensual

**Test ID:** UAT-FIN-001
**Feature:** Reportes Financieros
**Prioridad:** Alta
**Tester:** Jane Smith (Gerente de Finanzas)
**Fecha:** 2025-10-02

### Requisito de Negocio
Gerentes de finanzas necesitan generar reportes financieros mensuales comprensivos
que resuman ingresos, gastos y márgenes de ganancia por departamento.

### Pre-condiciones
- Usuario tiene rol de Gerente de Finanzas
- Existen datos financieros para Septiembre 2025
- Usuario está autenticado en el sistema

### Pasos de Prueba

1. Navegar a Reportes → Financiero → Resumen Mensual
   - **Esperado:** Página de Resumen Mensual carga en menos de 3 segundos
   - **Real:** _______________
   - **Pasa/Falla:** ___________

2. Seleccionar "Septiembre 2025" del dropdown de mes
   - **Esperado:** Mes seleccionado, formulario se actualiza
   - **Real:** _______________
   - **Pasa/Falla:** ___________

3. Seleccionar "Todos los Departamentos" o departamento específico
   - **Esperado:** Selección de departamento disponible
   - **Real:** _______________
   - **Pasa/Falla:** ___________

4. Hacer clic en botón "Generar Reporte"
   - **Esperado:** Reporte se genera en menos de 10 segundos, indicador de progreso se muestra
   - **Real:** _______________
   - **Pasa/Falla:** ___________

5. Revisar contenidos del reporte para exactitud
   - **Esperado:** Reporte incluye:
     - Ingresos totales por departamento
     - Gastos totales por categoría
     - Cálculos de margen de ganancia
     - Comparación mes a mes
     - Gráficos visuales (tendencia de ingresos, desglose de gastos)
   - **Real:** _______________
   - **Pasa/Falla:** ___________

6. Verificar que números del reporte coinciden con datos fuente
   - **Esperado:** Verificar manualmente que 3 transacciones de muestra aparecen correctamente
   - **Real:** _______________
   - **Pasa/Falla:** ___________

7. Exportar reporte como PDF
   - **Esperado:** PDF se descarga, mantiene formato, incluye todos los datos
   - **Real:** _______________
   - **Pasa/Falla:** ___________

8. Exportar reporte como Excel
   - **Esperado:** Excel se descarga, datos son editables, fórmulas incluidas
   - **Real:** _______________
   - **Pasa/Falla:** ___________

### Criterios de Aceptación de Negocio
- [  ] Reporte refleja exactamente datos financieros
- [  ] Reporte se genera dentro de tiempo aceptable (< 10 segundos)
- [  ] Formato de reporte cumple estándares de negocio
- [  ] Funcionalidad de exportación funciona para PDF y Excel
- [  ] Reporte es comprensible sin conocimiento técnico

### Comentarios/Issues
_____________________________________________________________________
_____________________________________________________________________

### Resultado General: PASA / FALLA / PASA CONDICIONALMENTE

**Firmado:** _____________________ **Fecha:** __________

Defectos Típicos Encontrados

  • Requisitos malinterpretados por equipo de desarrollo
  • Problemas de usabilidad (UI confusa, mensajes poco claros)
  • Reglas de negocio faltantes o casos extremos
  • Cálculos o lógica de negocio incorrectos
  • Reportes no coinciden con formato esperado
  • Workflow no coincide con proceso de negocio real
  • Problemas de performance con volúmenes de datos realistas

Mejores Prácticas

  1. Involucrar usuarios reales: No proxies o QA fingiendo ser usuarios
  2. Usar datos realistas: Enmascarar datos de producción si es necesario
  3. Documentar claramente: Usar lenguaje no técnico
  4. Programar tiempo adecuado: No apresurar fase UAT
  5. Definir criterios de aceptación claros: Pasa/falla binario por requisito
  6. Proporcionar capacitación: Ayudar a usuarios entender qué probar
  7. Recopilar feedback: Más allá de pasa/falla, recolectar sugerencias de mejora

Comparando Niveles de Testing

AspectoUnitIntegrationSystemUAT
Realizado porDesarrolladoresDesarrolladores/QAEquipo QAUsuarios de Negocio
EnfoqueComponentes individualesInteracciones de componentesSistema completoRequisitos de negocio
EntornoMáquina de desarrolladorEntorno de pruebaStaging/TestSimilar a producción
Base de PruebasCódigo, docs de diseñoSpecs de interfazRequisitosNecesidades de negocio
AutomatizaciónAltamente automatizadoMayormente automatizadoParcialmente automatizadoMayormente manual
Velocidad de EjecuciónMilisegundosSegundosMinutosHoras/Días
CuándoDurante codificaciónDespués de unit testingDespués de integrationAntes de release
Defectos TípicosErrores de lógicaProblemas de interfazBugs end-to-endBrechas de requisitos

Estrategia de Niveles de Testing

Costo de Defectos por Nivel

Defecto encontrado en: | Costo de corrección
-----------------------|---------------------
Unit Testing           | $           (1x)
Integration Testing    | $$          (10x)
System Testing         | $$$         (100x)
UAT                    | $$$$        (1000x)
Producción             | $$$$$       (10,000x)

Principio Clave: Encontrar defectos lo más temprano posible.

Distribución de Cobertura de Pruebas

Seguir la pirámide de testing:

        /\
       /  \      UAT (Manual)
      / 10%\     - Journeys críticos de usuario
     /------\    - Validación de negocio
    /        \
   /   30%    \  System Tests (Mayormente Automatizados)
  /    Tests   \ - Escenarios end-to-end
 /--------------\- Testing no funcional
/                \
/    60% Unit     \ Unit & Integration Tests (Completamente Automatizados)
/   & Integration  \- Rápidos, confiables, cobertura extensiva
/____Tests_________\

Conclusión

Comprender los niveles de testing permite a los equipos:

  • Estructurar actividades de testing lógicamente a través del ciclo de vida de desarrollo
  • Asignar responsabilidades apropiadamente entre desarrolladores, QA y usuarios de negocio
  • Optimizar detección de defectos detectando issues en la etapa más temprana y económica
  • Balancear testing manual y automatizado a través de diferentes niveles
  • Asegurar cobertura comprensiva desde componentes individuales hasta flujos de trabajo de negocio completos

Cada nivel de testing sirve un propósito distinto. El éxito proviene de ejecutar todos los niveles apropiadamente, con cobertura de pruebas adecuada, responsabilidades claras y énfasis en detección temprana de defectos a través de unit e integration testing mientras se valida valor de negocio a través de system testing y UAT. Para más información sobre testing funcional en estos niveles, consulta nuestra guía completa de pruebas funcionales.