Datos de prueba y estabilidad de ejecuciones en Postman

Capítulo 9

Tiempo estimado de lectura: 10 minutos

+ Ejercicio

Qué significa “datos de prueba estables” en Postman

En la práctica, la estabilidad de ejecuciones (baja flakiness) depende de que los datos usados por tus requests sean predecibles, aislados y trazables. Esto implica: evitar colisiones (dos ejecuciones creando el mismo “nombre”), controlar el tiempo (fechas consistentes), limpiar recursos creados (teardown) y registrar evidencia (IDs, respuestas y logs) para auditoría y depuración.

Estrategias operativas de datos de prueba (implementación técnica)

1) Datasets controlados (semilla conocida)

Un dataset controlado es un conjunto de valores “congelados” que se reutilizan de forma consistente. Es útil para pruebas que validan reglas de negocio sin depender de generación aleatoria. En Postman puedes implementarlo con variables de colección o de entorno, o con un objeto JSON en una variable.

Ejemplo: dataset en variable de colección

// En una variable de colección llamada testData (tipo string JSON) guarda algo como: {"user":{"name":"qa_user","emailDomain":"example.test"},"product":{"sku":"SKU-BASE-001"}}

Lectura del dataset en scripts

const testData = JSON.parse(pm.collectionVariables.get('testData'));

Recomendación: usa datasets controlados para entidades “base” (catálogos, SKUs, roles, permisos) y combina con generación dinámica solo para los campos que deben ser únicos.

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

2) Generación dinámica (unicidad y aislamiento por ejecución)

La generación dinámica reduce colisiones cuando varias personas o pipelines ejecutan la misma colección. La idea es crear un runId único por ejecución y derivar de él nombres, correos y referencias.

Paso a paso: crear un runId único una sola vez

  • En el primer request del flujo (o en un “Setup” dedicado), en Pre-request Script, inicializa runId si no existe.
  • Guarda el runId en variable de colección (para que sobreviva a toda la colección) o en entorno (si necesitas compartirlo entre colecciones).
if (!pm.collectionVariables.get('runId')) {  const runId = `${Date.now()}-${pm.info.iteration}-${pm.info.requestName}`;  pm.collectionVariables.set('runId', runId);}

Construir valores únicos

const runId = pm.collectionVariables.get('runId');const uniqueName = `pm-${runId}`;const uniqueEmail = `user+${runId}@example.test`;pm.collectionVariables.set('uniqueName', uniqueName);pm.collectionVariables.set('uniqueEmail', uniqueEmail);

Notas prácticas: Date.now() suele ser suficiente; si ejecutas en paralelo y quieres más entropía, agrega un random corto.

const rand = Math.random().toString(16).slice(2, 8);const runId = `${Date.now()}-${rand}`;

3) Limpieza (teardown) para no contaminar el entorno

El teardown consiste en borrar (o revertir) los recursos creados durante la ejecución. Esto evita que el dataset “crezca” indefinidamente y reduce fallos por límites, duplicados o reglas de unicidad.

Patrón recomendado: cada vez que crees un recurso, guarda su ID en una lista; al final, recorre la lista y elimina.

Control de colisiones: IDs y nombres únicos sin fricción

Guardar IDs relevantes para auditoría y teardown

Cuando un request crea un recurso, captura el ID desde el response y guárdalo. Además, registra el ID en una lista de “recursos a borrar”.

// Tests tab del request que crea un recursoconst json = pm.response.json();const id = json.id || json.data?.id;pm.test('Se obtuvo id', () => pm.expect(id).to.exist);pm.collectionVariables.set('lastCreatedId', id);// Lista para teardown (array JSON en string)const key = 'createdResourceIds';const current = JSON.parse(pm.collectionVariables.get(key) || '[]');current.push(id);pm.collectionVariables.set(key, JSON.stringify(current));

Si creas distintos tipos de recursos, guarda un registro estructurado (tipo y id) para borrar con el endpoint correcto.

const key = 'createdResources';const current = JSON.parse(pm.collectionVariables.get(key) || '[]');current.push({ type: 'user', id });pm.collectionVariables.set(key, JSON.stringify(current));

Evitar colisiones en entornos compartidos

En entornos compartidos (mismo ambiente para varios testers), el riesgo principal es que dos ejecuciones usen la misma variable “global” o “de entorno” y se pisen. Para minimizarlo:

  • Prefiere variables de colección para datos de una ejecución (aisladas al run de la colección).
  • Si debes escribir en entorno compartido, usa claves “namespaced” por runId (por ejemplo, userId__<runId>), o guarda un objeto JSON con mapa por runId.
  • No reutilices variables genéricas como userId si hay concurrencia; usa userId_currentRun o un mapa.

Ejemplo: mapa por runId en una sola variable

const runId = pm.collectionVariables.get('runId');const key = 'runState';const state = JSON.parse(pm.environment.get(key) || '{}');state[runId] = state[runId] || {};state[runId].userId = pm.collectionVariables.get('lastCreatedId');pm.environment.set(key, JSON.stringify(state));

Control de fechas y tiempo para reducir flakiness

Fechas deterministas (congelar “hoy”)

Muchos fallos intermitentes vienen de zonas horarias, cambios de día durante la ejecución o validaciones sensibles al tiempo. Una técnica simple es fijar un “now” al inicio y derivar todas las fechas desde ahí.

Paso a paso

  • En un Setup, fija baseNow en ISO.
  • Deriva fechas relativas (por ejemplo, +7 días) desde baseNow.
if (!pm.collectionVariables.get('baseNow')) {  pm.collectionVariables.set('baseNow', new Date().toISOString());}const baseNow = new Date(pm.collectionVariables.get('baseNow'));const plusDays = (d, days) => {  const x = new Date(d.getTime());  x.setUTCDate(x.getUTCDate() + days);  return x.toISOString();};pm.collectionVariables.set('dateToday', baseNow.toISOString());pm.collectionVariables.set('datePlus7', plusDays(baseNow, 7));

Recomendación: usa UTC (métodos setUTCDate, getUTCDate) para evitar diferencias por zona horaria.

Evitar aserciones frágiles con timestamps

Si el API devuelve timestamps generados por el servidor, evita comparar igualdad exacta. En su lugar, valida formato y rango.

const json = pm.response.json();pm.test('createdAt es ISO', () => {  pm.expect(json.createdAt).to.match(/^\d{4}-\d{2}-\d{2}T/);});pm.test('createdAt no es futuro lejano', () => {  const t = new Date(json.createdAt).getTime();  const now = Date.now();  pm.expect(t).to.be.below(now + 5 * 60 * 1000); // 5 min tolerancia});

Minimizar flakiness: prácticas técnicas en requests y scripts

1) Reintentos controlados (solo cuando aplica)

Si tu sistema tiene consistencia eventual (por ejemplo, un recurso tarda en estar disponible), puedes implementar un reintento limitado. En Postman, una forma práctica es re-ejecutar el request actual con postman.setNextRequest y un contador.

// Tests tab del request que consulta disponibilidadconst maxRetries = 3;const retryKey = 'retryCount';const retryCount = Number(pm.collectionVariables.get(retryKey) || 0);if (pm.response.code === 404 && retryCount < maxRetries) {  pm.collectionVariables.set(retryKey, retryCount + 1);  postman.setNextRequest(pm.info.requestName); // reintenta el mismo request} else {  pm.collectionVariables.unset(retryKey);}

Úsalo con cuidado: reintentar todo oculta problemas reales. Limítalo a endpoints conocidos por consistencia eventual.

2) Aislar dependencias: no reutilizar recursos “mutables”

Evita que múltiples ejecuciones modifiquen el mismo recurso (por ejemplo, el mismo usuario). Si necesitas un recurso base, clónalo por ejecución (con nombre único) o crea uno nuevo y bórralo al final.

3) Validaciones robustas: menos igualdad exacta, más invariantes

Para estabilidad, prioriza invariantes: presencia de campos, tipos, rangos, estados válidos, y relaciones (por ejemplo, el ID del response coincide con el ID solicitado). Evita aserciones sobre orden de arrays si no está garantizado.

Teardown básico: borrar recursos creados

Opción A: request(s) dedicados de limpieza al final

Crea un folder “Teardown” al final de la colección con requests de borrado. Cada request toma IDs desde la lista guardada.

Ejemplo: borrar usuarios desde lista

// Pre-request Script del request DELETE /users/:idconst resources = JSON.parse(pm.collectionVariables.get('createdResources') || '[]');const next = resources.find(r => r.type === 'user');if (!next) {  postman.setNextRequest(null); // o salta al siguiente teardown  return;}pm.collectionVariables.set('deleteUserId', next.id);
// Tests tab: tras borrar, remover de la lista y continuarconst resources = JSON.parse(pm.collectionVariables.get('createdResources') || '[]');const id = pm.collectionVariables.get('deleteUserId');const remaining = resources.filter(r => !(r.type === 'user' && String(r.id) === String(id)));pm.collectionVariables.set('createdResources', JSON.stringify(remaining));postman.setNextRequest(pm.info.requestName); // repite hasta vaciar

Ventaja: simple y explícito. Consideración: requiere endpoints de borrado disponibles y permisos adecuados.

Opción B: teardown “best-effort” (no fallar la suite por limpieza)

Si el objetivo principal es validar funcionalidad, la limpieza puede ser “best-effort”: registra si falló, pero no rompas toda la ejecución. En tests, evita pm.test estrictos para el teardown o marca advertencias en consola.

if (pm.response.code !== 200 && pm.response.code !== 204 && pm.response.code !== 404) {  console.warn('Teardown: respuesta inesperada', pm.response.code, pm.response.text());}

Manejo de entornos compartidos: reglas prácticas

ProblemaImplementación recomendada
Variables pisadas por ejecuciones simultáneasGuardar estado por runId (mapa JSON) o usar variables de colección para estado efímero
Datos “huérfanos” por ejecuciones interrumpidasTeardown al final + endpoint de limpieza por prefijo (si existe) usando runId en nombres
Auditoría difícil (no se sabe qué creó cada run)Registrar runId, IDs creados y timestamps en una variable auditLog

Bitácora de auditoría en una variable

Guarda un log estructurado por ejecución con eventos clave (creación/borrado, IDs, endpoints). Esto ayuda a reproducir y explicar resultados.

const runId = pm.collectionVariables.get('runId');const key = 'auditLog';const log = JSON.parse(pm.collectionVariables.get(key) || '[]');log.push({  ts: new Date().toISOString(),  runId,  request: pm.info.requestName,  method: pm.request.method,  url: pm.request.url.toString(),  status: pm.response.code,  ids: { lastCreatedId: pm.collectionVariables.get('lastCreatedId') }});pm.collectionVariables.set(key, JSON.stringify(log));

Registro de evidencia: respuestas, consola y almacenamiento de IDs

1) Capturar “snapshot” del response (sanitizado)

Para evidencia, guarda una versión acotada del response (por ejemplo, solo campos relevantes) en una variable. Evita almacenar tokens o datos sensibles.

const json = pm.response.json();const snapshot = {  id: json.id,  status: json.status,  createdAt: json.createdAt};pm.collectionVariables.set('lastResponseSnapshot', JSON.stringify(snapshot));

2) Logs en consola con contexto

Usa console.log para imprimir runId, IDs y decisiones (reintentos, saltos). Esto acelera el diagnóstico cuando un run falla en CI.

console.log('runId=', pm.collectionVariables.get('runId'));console.log('createdResources=', pm.collectionVariables.get('createdResources'));

3) Persistir IDs clave para revisión

Además de la lista para teardown, guarda IDs “de negocio” (por ejemplo, orderId, invoiceId) en variables con nombre claro. Si hay múltiples, usa arrays.

const key = 'orderIds';const arr = JSON.parse(pm.collectionVariables.get(key) || '[]');arr.push(pm.collectionVariables.get('lastCreatedId'));pm.collectionVariables.set(key, JSON.stringify(arr));

Guía práctica: plantilla operativa para una ejecución estable

Paso 1: Setup (una vez por ejecución)

  • Inicializa runId y baseNow.
  • Carga testData (dataset controlado) y deriva valores únicos.
  • Inicializa contenedores: createdResources, auditLog.
if (!pm.collectionVariables.get('runId')) {  pm.collectionVariables.set('runId', `${Date.now()}-${Math.random().toString(16).slice(2,8)}`);}if (!pm.collectionVariables.get('baseNow')) {  pm.collectionVariables.set('baseNow', new Date().toISOString());}if (!pm.collectionVariables.get('createdResources')) {  pm.collectionVariables.set('createdResources', '[]');}if (!pm.collectionVariables.get('auditLog')) {  pm.collectionVariables.set('auditLog', '[]');}const runId = pm.collectionVariables.get('runId');pm.collectionVariables.set('uniqueEmail', `user+${runId}@example.test`);pm.collectionVariables.set('uniqueName', `pm-${runId}`);

Paso 2: En cada creación, guardar ID y registrar evidencia

  • Extrae ID del response.
  • Agrega a createdResources con tipo.
  • Guarda snapshot y agrega entrada a auditLog.

Paso 3: En lecturas/validaciones sensibles al tiempo

  • Usa baseNow para fechas en requests.
  • Valida timestamps por formato/rango, no por igualdad exacta.

Paso 4: Teardown al final

  • Recorre createdResources y borra en orden seguro (por ejemplo, primero hijos, luego padres).
  • Teardown best-effort si el objetivo es no bloquear el pipeline por limpieza.

Ahora responde el ejercicio sobre el contenido:

¿Qué práctica ayuda más a reducir colisiones y mejorar el aislamiento cuando varias ejecuciones de Postman corren en paralelo en un entorno compartido?

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

¡Tú error! Inténtalo de nuevo.

Un runId único permite construir valores únicos por ejecución y evitar que runs simultáneos se pisen. Usar variables de colección ayuda a aislar el estado del run y reduce colisiones en entornos compartidos.

Siguiente capítulo

Ejecución automatizada con Collection Runner y flujos parametrizados en Postman

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

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.