Tests en Postman: aserciones y validación de contratos de API

Capítulo 7

Tiempo estimado de lectura: 11 minutos

+ Ejercicio

Qué es un test en Postman y qué problema resuelve

En Postman, un test es un script (JavaScript) que se ejecuta después de recibir la respuesta de una request. Su objetivo es convertir una verificación manual (“se ve bien”) en aserciones repetibles sobre: código de estado, tiempos, headers, estructura y contenido del JSON, y reglas de negocio. Cuando estos tests se ejecutan en Collection Runner o en CI, actúan como una red de seguridad para detectar regresiones.

Guía práctica: crear aserciones esenciales en la pestaña Tests

1) Aserciones de status code

Valida que el endpoint responda con el código esperado. Esto detecta cambios de comportamiento (por ejemplo, un 200 que pasa a 204 o un 201 que se convierte en 200).

pm.test("Status code es 200", function () {  pm.response.to.have.status(200);});

Si tu API usa códigos diferentes según operación, crea tests específicos por request (por ejemplo, 201 en creación, 204 en borrado).

2) Aserciones de tiempo de respuesta

El tiempo no solo es performance: también ayuda a detectar degradaciones o problemas de infraestructura. Define umbrales realistas por entorno.

pm.test("Tiempo de respuesta < 800ms", function () {  pm.expect(pm.response.responseTime).to.be.below(800);});

3) Aserciones de headers

Verifica headers críticos del contrato (por ejemplo, tipo de contenido, caching, correlación). Un caso típico es asegurar JSON.

Continúa en nuestra aplicación.
  • Escuche el audio con la pantalla apagada.
  • Obtenga un certificado al finalizar.
  • ¡Más de 5000 cursos para que explores!
O continúa leyendo más abajo...
Download App

Descargar la aplicación

pm.test("Content-Type es JSON", function () {  pm.response.to.have.header("Content-Type");  pm.expect(pm.response.headers.get("Content-Type")).to.match(/application\/json/i);});

Si tu API usa un header de trazabilidad (por ejemplo X-Request-Id), valida su presencia y formato.

pm.test("Incluye X-Request-Id", function () {  const rid = pm.response.headers.get("X-Request-Id");  pm.expect(rid, "X-Request-Id debe existir").to.be.a("string").and.not.be.empty;});

4) Aserciones sobre contenido JSON

Primero, asegúrate de que la respuesta sea JSON parseable y luego valida campos.

pm.test("Body es JSON válido", function () {  pm.response.to.be.json;});const body = pm.response.json();

Ejemplo: validar que exista un objeto data y que tenga un id.

pm.test("data.id existe", function () {  const body = pm.response.json();  pm.expect(body).to.have.property("data");  pm.expect(body.data).to.have.property("id");});

Validaciones de contrato a nivel de campos: obligatorios, tipos, rangos y reglas simples

Estas validaciones son el núcleo de la “calidad funcional” del contrato. No solo verifican que el endpoint responda, sino que responda con datos coherentes.

1) Campos obligatorios (required)

Define qué campos deben existir siempre. Si un campo es opcional, no lo marques como obligatorio: en su lugar, valida su tipo solo si existe.

pm.test("Campos obligatorios presentes", function () {  const b = pm.response.json();  const required = ["id", "name", "status"];  required.forEach((k) => {    pm.expect(b.data, `Falta campo obligatorio: ${k}`).to.have.property(k);  });});

2) Tipos de datos

Valida tipos para evitar cambios silenciosos (por ejemplo, id de número a string). Postman usa Chai (pm.expect).

pm.test("Tipos correctos", function () {  const d = pm.response.json().data;  pm.expect(d.id, "id debe ser number").to.be.a("number");  pm.expect(d.name, "name debe ser string").to.be.a("string");  pm.expect(d.active, "active debe ser boolean").to.be.a("boolean");});

3) Rangos y límites

Útil para montos, edades, porcentajes, paginación, etc.

pm.test("Rangos válidos", function () {  const d = pm.response.json().data;  pm.expect(d.score, "score debe estar entre 0 y 100").to.be.within(0, 100);  pm.expect(d.itemsCount, "itemsCount no puede ser negativo").to.be.at.least(0);});

4) Reglas de negocio simples

Ejemplos típicos: consistencia entre campos, estados permitidos, fechas lógicas.

pm.test("Reglas de negocio: status permitido y consistencia", function () {  const d = pm.response.json().data;  pm.expect(d.status).to.be.oneOf(["NEW", "ACTIVE", "SUSPENDED"]);  if (d.status === "SUSPENDED") {    pm.expect(d.suspensionReason, "Si está SUSPENDED debe haber motivo").to.be.a("string").and.not.be.empty;  }});

Para fechas, valida formato y orden (sin depender de librerías externas).

pm.test("Fechas coherentes", function () {  const d = pm.response.json().data;  const created = Date.parse(d.createdAt);  const updated = Date.parse(d.updatedAt);  pm.expect(created, "createdAt debe ser parseable").to.not.be.NaN;  pm.expect(updated, "updatedAt debe ser parseable").to.not.be.NaN;  pm.expect(updated, "updatedAt debe ser >= createdAt").to.be.at.least(created);});

Validación de contratos con JSON Schema (JSON Schema Validation)

Las aserciones por campo son claras, pero escalan mal cuando el payload crece. La validación por JSON Schema permite describir la forma del JSON (tipos, required, enums, formatos) y validar la respuesta completa contra ese contrato.

1) Preparar el esquema por recurso

Recomendación práctica: mantener un esquema por recurso/endpoint (por ejemplo, User.json, Order.json, Error.json) y versionarlos junto con la colección. En Postman puedes guardarlos como:

  • Variables de colección: schema_user, schema_order, etc. (cómodo para reutilizar en requests de la misma colección).
  • Archivos en el repo y cargarlos en CI (si tu pipeline inyecta el contenido como variables). En Postman UI, lo más directo es colección/entorno.

Ejemplo de esquema mínimo para data (guardado en una variable de colección schema_user):

{  "type": "object",  "required": ["data"],  "properties": {    "data": {      "type": "object",      "required": ["id", "name", "status"],      "properties": {        "id": {"type": "number"},        "name": {"type": "string", "minLength": 1},        "status": {"type": "string", "enum": ["NEW", "ACTIVE", "SUSPENDED"]},        "active": {"type": "boolean"}      },      "additionalProperties": true    }  },  "additionalProperties": true}

2) Validar la respuesta contra el esquema

Postman incluye tv4 en muchos entornos de ejecución clásicos; en otros casos, se usa Ajv como librería externa, pero aquí nos enfocamos en lo que suele estar disponible sin dependencias. Primero, recupera el esquema desde variables y valida.

pm.test("Contrato JSON Schema: User", function () {  const schemaRaw = pm.collectionVariables.get("schema_user");  pm.expect(schemaRaw, "No existe schema_user en variables de colección").to.be.a("string").and.not.be.empty;  const schema = JSON.parse(schemaRaw);  const data = pm.response.json();  const result = tv4.validateMultiple(data, schema);  if (!result.valid) {    const details = result.errors.map(e => `Ruta: ${e.dataPath || '/'} | Regla: ${e.message}`).join("; ");    pm.expect.fail(`Fallo de esquema: ${details}`);  }});

Notas prácticas:

  • validateMultiple permite listar múltiples errores, lo que acelera el diagnóstico.
  • Usa pm.expect.fail para que el reporte muestre un mensaje claro y accionable.
  • Si tu API envuelve respuestas (por ejemplo { data, meta }), el esquema debe reflejar ese wrapper.

3) Mantener esquemas por recurso (estrategia de organización)

EnfoqueCómo se guardaCuándo conviene
Esquema por requestVariable local en el scriptPrototipos rápidos, payload pequeño
Esquema por recursoVariables de colección (schema_user, schema_order)Reutilización entre requests (GET/POST/PUT del mismo recurso)
Esquema por versiónschema_user_v1, schema_user_v2APIs versionadas o migraciones graduales
Esquema de error comúnschema_errorEstandarizar respuestas 4xx/5xx

Consejo: evita duplicar esquemas casi iguales. Si hay pequeñas variaciones (por ejemplo, en POST el id puede no venir), crea esquemas específicos: schema_user_get y schema_user_create_response.

Casos negativos: validar errores esperados (4xx/5xx) y consistencia

Probar “lo que sale bien” no es suficiente. Los casos negativos garantizan que el sistema falle de forma predecible y con mensajes consistentes para clientes.

1) Aserción de status code de error esperado

Ejemplo: request con parámetro inválido debe devolver 400.

pm.test("Error esperado: 400", function () {  pm.response.to.have.status(400);});

2) Contrato de error consistente (código interno, mensaje, detalles)

Define un formato estándar de error, por ejemplo:

{  "error": {    "code": "VALIDATION_ERROR",    "message": "Invalid input",    "details": [ {"field": "email", "issue": "invalid"} ]  }}

Valida estructura y tipos:

pm.test("Contrato de error consistente", function () {  const b = pm.response.json();  pm.expect(b).to.have.property("error");  pm.expect(b.error).to.have.property("code").that.is.a("string");  pm.expect(b.error).to.have.property("message").that.is.a("string");  pm.expect(b.error).to.have.property("details");  pm.expect(b.error.details).to.be.an("array");});

Valida códigos internos (útil para soporte y trazabilidad):

pm.test("Código interno de error permitido", function () {  const code = pm.response.json().error.code;  pm.expect(code).to.be.oneOf(["VALIDATION_ERROR", "NOT_FOUND", "UNAUTHORIZED", "FORBIDDEN", "CONFLICT", "INTERNAL_ERROR"]);});

3) Validación por JSON Schema para errores

Guarda un schema_error y reutilízalo en todas las requests negativas.

pm.test("JSON Schema: Error", function () {  const schema = JSON.parse(pm.collectionVariables.get("schema_error"));  const result = tv4.validateMultiple(pm.response.json(), schema);  if (!result.valid) {    pm.expect.fail("Fallo de esquema (error): " + result.errors.map(e => e.message).join(" | "));  }});

4) Manejo de 5xx esperados en entornos de prueba

A veces se prueban fallos controlados (por ejemplo, dependencia caída simulada). Si esperas un 503, valida que el error sea informativo y consistente (sin filtrar stack traces).

pm.test("503 controlado sin fuga de información", function () {  pm.response.to.have.status(503);  const raw = pm.response.text();  pm.expect(raw).to.not.match(/Exception|StackTrace|NullPointer/i);});

Mensajes de fallo claros: hacer que el reporte sea accionable

Un test útil no solo falla: explica qué falló y dónde. Usa mensajes en pm.expect y construye detalles cuando iteras arrays.

pm.test("Validación de lista: cada item tiene id y name", function () {  const items = pm.response.json().data.items;  pm.expect(items, "data.items debe ser array").to.be.an("array");  items.forEach((it, idx) => {    pm.expect(it.id, `items[${idx}].id requerido`).to.exist;    pm.expect(it.name, `items[${idx}].name requerido`).to.be.a("string").and.not.be.empty;  });});

Set de tests base reutilizable para estandarizar calidad

Para no repetir lógica en cada request, crea un “pack” de tests base que puedas copiar/pegar y ajustar con variables. La idea es que todas las requests compartan un mínimo de calidad: status, tiempo, headers, JSON válido y (si aplica) esquema.

Plantilla: tests base para respuestas exitosas JSON

Configura variables de colección por request (o por carpeta) para parametrizar:

  • expected_status (ej. 200, 201)
  • max_response_time_ms (ej. 800)
  • schema_key (ej. schema_user, schema_order)
// ===== Tests base reutilizables (Success JSON) =====const expectedStatus = Number(pm.collectionVariables.get("expected_status") || 200);const maxTime = Number(pm.collectionVariables.get("max_response_time_ms") || 1000);const schemaKey = pm.collectionVariables.get("schema_key");pm.test(`Status code es ${expectedStatus}`, function () {  pm.response.to.have.status(expectedStatus);});pm.test(`Tiempo de respuesta < ${maxTime}ms`, function () {  pm.expect(pm.response.responseTime).to.be.below(maxTime);});pm.test("Content-Type es JSON", function () {  pm.response.to.have.header("Content-Type");  pm.expect(pm.response.headers.get("Content-Type")).to.match(/application\/json/i);});pm.test("Body es JSON válido", function () {  pm.response.to.be.json;});if (schemaKey) {  pm.test(`JSON Schema válido: ${schemaKey}`, function () {    const schemaRaw = pm.collectionVariables.get(schemaKey);    pm.expect(schemaRaw, `No existe variable de colección: ${schemaKey}`).to.be.a("string").and.not.be.empty;    const schema = JSON.parse(schemaRaw);    const result = tv4.validateMultiple(pm.response.json(), schema);    if (!result.valid) {      const details = result.errors.map(e => `Ruta: ${e.dataPath || '/'} | ${e.message}`).join("; ");      pm.expect.fail(`Fallo de esquema (${schemaKey}): ${details}`);    }  });}

Plantilla: tests base para errores esperados

Parametriza el status de error y el esquema de error común.

// ===== Tests base reutilizables (Expected Error) =====const expectedErrorStatus = Number(pm.collectionVariables.get("expected_error_status") || 400);const errorSchemaKey = pm.collectionVariables.get("error_schema_key") || "schema_error";pm.test(`Status code de error es ${expectedErrorStatus}`, function () {  pm.response.to.have.status(expectedErrorStatus);});pm.test("Contrato de error: JSON válido", function () {  pm.response.to.be.json;});pm.test(`JSON Schema válido (error): ${errorSchemaKey}`, function () {  const schemaRaw = pm.collectionVariables.get(errorSchemaKey);  pm.expect(schemaRaw, `No existe variable de colección: ${errorSchemaKey}`).to.be.a("string").and.not.be.empty;  const schema = JSON.parse(schemaRaw);  const result = tv4.validateMultiple(pm.response.json(), schema);  if (!result.valid) {    pm.expect.fail("Fallo de esquema (error): " + result.errors.map(e => e.message).join(" | "));  }});pm.test("Código interno de error presente", function () {  const b = pm.response.json();  pm.expect(b).to.have.property("error");  pm.expect(b.error).to.have.property("code").that.is.a("string").and.not.be.empty;});

Con estas plantillas, puedes estandarizar rápidamente: cada request define sus variables (status esperado, umbral de tiempo, esquema) y hereda el mismo nivel de exigencia. Esto reduce la variabilidad entre colecciones y hace que los reportes sean comparables entre equipos y servicios.

Ahora responde el ejercicio sobre el contenido:

¿Cuál es la ventaja principal de validar la respuesta de una API con JSON Schema en Postman en lugar de crear muchas aserciones por campo?

¡Tienes razón! Felicitaciones, ahora pasa a la página siguiente.

¡Tú error! Inténtalo de nuevo.

La validación con JSON Schema permite definir el contrato del payload (estructura y reglas como tipos, campos requeridos y enums) y comprobar la respuesta completa, lo que resulta más mantenible cuando el JSON crece frente a muchas aserciones por campo.

Siguiente capítulo

Encadenamiento de requests en Postman para flujos end-to-end

Arrow Right Icon
Portada de libro electrónico gratuitaPostman en la Práctica: Pruebas de API desde Cero hasta la Automatización
58%

Postman en la Práctica: Pruebas de API desde Cero hasta la Automatización

Nuevo curso

12 páginas

Descarga la aplicación para obtener una certificación gratuita y escuchar cursos en segundo plano, incluso con la pantalla apagada.