Pruebas de API con Postman
Qué prueba Postman (y qué no)
Sección titulada «Qué prueba Postman (y qué no)»Postman es un cliente HTTP: arma una petición real, la envía por la red, y solo puede ver dos cosas, lo que salió (verbo, URL, headers, body) y lo que volvió (status, headers, body). No lee el código fuente ni sabe en qué framework o lenguaje está escrito el backend: prueba el contrato HTTP desde afuera, exactamente como lo haría el front en Angular o cualquier otro cliente real.
Esto es lo que se llama una prueba de caja negra: verifica que la caja responda como se espera, sin abrirla para revisar por dentro. El otro extremo son las pruebas con JUnit: prueban un método Java (la unidad es el método) y se escriben en Java.
Qué más puede hacer Postman
Sección titulada «Qué más puede hacer Postman»En este curso se usan Collections, Environments y Tests, pero Postman ofrece bastante más. Vale la pena saber que existe, para cuando se necesite en un proyecto real:
- Pre-request scripts: código que corre justo antes de enviar la petición, por ejemplo para calcular una fecha o armar un token.
- Collection Runner: corre todas las peticiones de una Collection en secuencia, incluso repitiendo el ciclo con un archivo de datos (CSV o JSON).
- Newman: el mismo Collection Runner, pero desde la terminal en vez de la aplicación de Postman. Sirve para automatizar la ejecución de las pruebas, por ejemplo como parte de un pipeline de Integración Continua. Se instala en el taller de ambiente de desarrollo.
- Mock Servers: simulan las respuestas de una API que todavía no existe, para que el front pueda avanzar en paralelo.
- Monitors: ejecutan una Collection automáticamente según un horario, para detectar si un servicio se cae.
- Documentación y Workspaces: generan documentación navegable de la API a partir de la Collection, y permiten compartirla con el equipo.
Principios para diseñar una prueba de API
Sección titulada «Principios para diseñar una prueba de API»Antes de escribir un pm.test(), dos preguntas:
- ¿Qué datos necesita la prueba? Si se va a consultar un artista por su
id, ese artista tiene que existir de antemano: o ya está en los datos de
prueba, o se crea con un
POSTjusto antes (se ve en “Tests encadenados”, más abajo). - ¿Qué se va a verificar, y en qué escenarios? Es la misma idea de JUnit: un escenario positivo verifica el caso feliz (el código de estado esperado, la forma del body); un escenario negativo verifica qué pasa cuando algo sale mal o se sale de lo común (un id que no existe, una lista vacía, un dato duplicado). La estrategia mínima para cada endpoint es al menos un escenario positivo y uno negativo.
Qué es un test en Postman
Sección titulada «Qué es un test en Postman»Después de recibir una respuesta HTTP, Postman ejecuta JavaScript para verificar formalmente lo esperado. Sin tests hay que revisar visualmente status, body y headers; con tests la verificación es repetible y automática en toda la Collection.
- Enviar la petición HTTP.
- Recibir status, headers, body y tiempo de respuesta.
- Ejecutar el JavaScript de la pestaña Scripts (opción Post-response).
- Mostrar
PASSoFAILpara cadapm.test()en Test Results.
Anatomía de pm.test() y pm.expect()
Sección titulada «Anatomía de pm.test() y pm.expect()»pm.test("El artista tiene id y nombre", function () { const artista = pm.response.json(); pm.expect(artista).to.have.property("id"); pm.expect(artista).to.have.property("nombre");});pmes el objeto global para respuesta, entorno y tests.pm.test(nombre, función)define el caso visible en Test Results.- el nombre expresa qué se verifica.
- la función contiene una o más aserciones.
pm.expect(valor real)inicia una aserción Chai y la cadena posterior expresa el valor esperado.
Aserciones esenciales
Sección titulada «Aserciones esenciales»pm.expect(pm.response.code).to.equal(200);pm.expect(body).to.be.an("array");pm.expect(body.length).to.be.above(0);pm.expect(artista).to.have.property("albumes");pm.expect(artista.nombre).to.be.a("string");pm.expect(artista.albumes).to.be.empty;pm.expect(pm.response.responseTime).to.be.below(500);pm.expect(pm.response.headers.get("Content-Type")) .to.include("application/json");Qué verificar más allá del status
Sección titulada «Qué verificar más allá del status»El status dice si la petición funcionó, no si lo hizo bien. Una respuesta 200 con el cuerpo equivocado, o un 204 que nunca borró nada, pasa un test que solo mira el código. Conviene verificar cinco capas, de la más superficial a la más profunda:
| Capa | Qué se verifica | Ejemplo |
|---|---|---|
| Status | El código esperado | 201 al crear |
| Cabeceras | El formato de la respuesta | Content-Type incluye application/json |
| Forma del cuerpo | Qué campos hay y de qué tipo | albumes es un arreglo; id es un número |
| Valores | El contenido coincide con lo enviado o con la URL | El nombre es el que se envió; el id es el de la URL |
| Efectos | Un GET posterior confirma que el cambio ocurrió |
Tras un DELETE, el GET responde 404 |
En los errores, además del status, se verifica el cuerpo: el back responde un ApiError (status, message, timestamp) y el message debe nombrar la causa, porque es el texto que el front le muestra a la persona.
Patrones por operación
Sección titulada «Patrones por operación»Cada patrón siguiente aplica el principio de escenarios positivos y negativos a un verbo HTTP distinto.
GET de una colección
Sección titulada «GET de una colección»Verifica 200, que el body sea un arreglo no vacío, que cada artista tenga id y nombre, que albumes exista como arreglo para confirmar ArtistaDTOCompleto, y que Content-Type incluya application/json.
GET por identificador
Sección titulada «GET por identificador»Verifica que el body sea un objeto y no un arreglo, que el id coincida con el de la URL, que nombre sea un string no vacío y que albumes sea un arreglo. Cada álbum trae id y titulo.
POST exitoso
Sección titulada «POST exitoso»Verifica 201 Created, un identificador numérico positivo asignado por el servidor y que nombre coincida con el enviado. La respuesta de un POST es el DTO básico, sin albumes: la colección se ve en el GET por identificador. Este back no envía el header Location, así que no se verifica.
const nuevo = pm.response.json();
pm.test("Status code es 201 Created", () => pm.expect(pm.response.code).to.equal(201));pm.test("id fue asignado por el servidor", () => pm.expect(nuevo.id).to.be.above(0));pm.test("El nombre coincide con el enviado", () => pm.expect(nuevo.nombre).to.equal(pm.environment.get("nombreArtista")));PUT, DELETE y errores
Sección titulada «PUT, DELETE y errores»- PUT verifica
200, que el identificador no cambie, que los campos enviados se actualicen, que unGETposterior confirme el cambio y que los álbumes se conserven. - DELETE verifica
204 No Content, sin cuerpo, y que unGETposterior al mismo identificador responda404. - una regla violada, por ejemplo un nombre repetido, verifica
400y un cuerpoApiErrorconstatus: 400, unmessageque nombre la regla y untimestamp. - un identificador inexistente verifica
404, un cuerpoApiErrorsin propiedadnombrey un mensaje que diga que el recurso no existe.
Laboratorio de respuestas
Cambiar la respuesta simulada, ejecutar los tests y observar por qué pasan o fallan.
Código de estado
Respuesta simulada
Status recibido: 200 · 38 ms
Tests que se ejecutarán
pm.expect(pm.response.code).to.equal(200);
Test Results
Selecciona una respuesta y ejecuta.
Tests encadenados
Sección titulada «Tests encadenados»// POST: guardar el id generadopm.environment.set("artistaId", nuevo.id);
// GET: usarlo en /artistas/{{artistaId}}pm.expect(pm.response.json().id) .to.equal(Number(pm.environment.get("artistaId")));
// DELETE: limpiar la variablepm.environment.unset("artistaId");El encadenamiento crea un recurso, consulta el mismo identificador y finalmente lo elimina. Las variables de entorno evitan copiar manualmente el valor entre requests.