Saltar al contenido principal

Pruebas (Testing)

🎯 Objetivo

Regla

15.1: Se debe implementar una estrategia de pruebas exhaustiva y automatizada para todas las APIs REST, cubriendo diferentes niveles (unitarias, integración, contrato, E2E). 15.2: El objetivo es asegurar la correctitud, fiabilidad, rendimiento y seguridad de la API, y facilitar la refactorización y evolución continua.

📖 Concepto y Definición

Regla

15.3: Las pruebas de API son obligatorias y deben incluir como mínimo los siguientes tipos:

  • Pruebas Unitarias: Deben verificar la lógica de negocio aislada dentro de los componentes individuales del servicio (ej. controladores, servicios, modelos) sin depender de componentes externos como bases de datos o servicios de terceros (usando mocks/stubs).
  • Pruebas de Integración: Deben verificar la interacción entre los componentes internos de la API y con servicios externos como bases de datos. No deben probar la interacción con otras APIs externas (eso sería E2E).
  • Pruebas de Contrato (API): Deben verificar que la API cumple con su contrato definido (ej. especificación OpenAPI). Esto incluye validar URIs, métodos, encabezados, códigos de estado, y la estructura y tipos de datos de las solicitudes/respuestas.
  • Pruebas End-to-End (E2E) (Recomendado): Pueden verificar flujos completos a través de la API, posiblemente involucrando otras APIs o sistemas, desde la perspectiva del cliente.
  • Pruebas de Seguridad (Recomendado): Deben evaluar la API contra vulnerabilidades comunes (ver Sección 7).
  • Pruebas de Rendimiento (Recomendado): Deben medir la latencia, el throughput y la escalabilidad de la API bajo carga.

🤔 ¿Por qué es Importante? / Beneficios Clave (Contexto)

  • Calidad y Fiabilidad: Asegura que la API funcione como se espera.
  • Detección Temprana de Errores: Reduce el costo de arreglar bugs.
  • Confianza en Cambios: Facilita la refactorización y adición de nuevas funcionalidades.
  • Documentación Viva: Las pruebas (especialmente las de contrato) sirven como ejemplos de uso.
  • Regresión: Evita que funcionalidades previamente correctas se rompan.

✅ Buenas Prácticas y Recomendaciones Clave

Regla

15.4: Todas las pruebas deben ser automatizadas y ejecutadas como parte del pipeline de Integración Continua (CI) antes de cualquier despliegue. 15.5: Se debe aspirar a una alta cobertura de código con pruebas unitarias y de integración. 15.6: Las pruebas de contrato son obligatorias y deben validar la conformidad con la especificación OpenAPI (Norma 9.4). Se pueden usar herramientas que validen las interacciones HTTP contra el schema OAS. 15.7: Las pruebas deben cubrir casos de éxito, casos de error (ej. diferentes códigos 4xx, 5xx) y casos límite. 15.8: Los datos de prueba deben ser realistas y gestionados de forma que las pruebas sean repetibles y no interfieran entre sí. 15.9: Para pruebas de integración que involucren bases de datos, se debe usar una base de datos de prueba dedicada y asegurar que esté en un estado conocido antes de cada ejecución de prueba (ej. rollback de transacciones, limpieza de datos). 15.10: Se deben mockear o stubbear las dependencias externas (otras APIs, servicios de terceros) en pruebas unitarias y de integración para asegurar aislamiento y determinismo. 15.11: Las pruebas de seguridad y rendimiento, aunque listadas como recomendadas en 15.3, son altamente recomendadas y deben considerarse obligatorias para APIs críticas o expuestas públicamente.

Don'ts (Prohibido):

  • 15.12: No se debe desplegar código de API a producción sin que pasen todas las pruebas automatizadas relevantes.
  • 15.13: No se deben escribir pruebas frágiles que fallen con cambios menores no relacionados.
  • 15.14: No se deben depender de datos volátiles o entornos externos inestables para pruebas unitarias o de integración.
  • 15.15: No se deben ignorar los fallos de prueba.

💡 Ejemplos Prácticos (Ilustrativos)

Ejemplo 1: Prueba de Contrato (Pseudo-código con herramienta tipo Dredd o similar)

Asumiendo una especificación OpenAPI openapi.yaml:

// (Conceptual - la sintaxis depende de la herramienta)

// Hook para preparar datos antes de una prueba específica
hooks.before('/users > POST > 201', (transaction) => {
transaction.request.body = JSON.stringify({ username: 'newuser', email: 'new@example.com' });
});

// Prueba: POST /users crea un usuario y devuelve 201
// La herramienta validará que la solicitud y respuesta coincidan con openapi.yaml
// para el endpoint POST /users y la respuesta 201.

Ejemplo 2: Prueba de Integración (Ejemplo con un framework de testing de Node.js como Jest + Supertest)

const request = require('supertest');
const app = require('../app'); // Tu aplicación API
const db = require('../db'); // Módulo de base deatos

describe('GET /v1/users/:userId', () => {
beforeAll(async () => {
// Preparar base de datos de prueba
await db.query("INSERT INTO users (id, username) VALUES ('test-user-1', 'tester')");
});

afterAll(async () => {
// Limpiar base de datos de prueba
await db.query("DELETE FROM users WHERE id = 'test-user-1'");
await db.close();
});

it('debe devolver 200 y los datos del usuario si existe', async () => {
const response = await request(app).get('/v1/users/test-user-1');
expect(response.statusCode).toBe(200);
expect(response.body.data.userId).toBe('test-user-1');
expect(response.body.data.username).toBe('tester');
});

it('debe devolver 404 si el usuario no existe', async () => {
const response = await request(app).get('/v1/users/non-existent-user');
expect(response.statusCode).toBe(404);
expect(response.body.error.code).toBe('RESOURCE_NOT_FOUND'); // Validar formato de error (Norma 11.4)
});
});

🛠️ Herramientas y Consideraciones Adicionales (Contexto)

  • Frameworks de Pruebas Unitarias: Jest, Mocha, PyTest, JUnit, NUnit, etc. (dependiendo del lenguaje).
  • Bibliotecas de Aserción HTTP: Supertest (Node.js), REST Assured (Java), cliente HTTP del framework (Python: requests + pytest).
  • Herramientas de Pruebas de Contrato: Dredd, PactumJS, Prism (de Stoplight).
  • Mocks/Stubs: Sinon.JS (Node.js), Mockito (Java), unittest.mock (Python).
  • Pruebas de Carga: k6, JMeter, Locust, Artillery.
  • Escáneres de Seguridad: OWASP ZAP, Burp Suite.
  • Cobertura de Código: Istanbul (JS), Cobertura/JaCoCo (Java), coverage.py (Python).
  • Datos de Prueba: Se pueden usar bibliotecas de generación de datos falsos (ej. Faker.js) o estrategias de plantillas de datos.