TL;DR
- API testing verifica que servicios backend funcionan correctamente sin UI — más rápido y confiable que tests E2E
- Testea: status codes, cuerpo de respuesta, headers, manejo de errores, autenticación, validación de esquemas, performance
- Herramientas: Postman (manual/aprendizaje), REST Assured (Java), Supertest (Node.js), requests (Python)
- Automatiza en CI/CD — APIs cambian frecuentemente, atrapa breaking changes temprano
- Cubre happy path y escenarios de error (400s, 401, 404, 500)
- Valida esquemas de respuesta para prevenir drift de contratos entre frontend y backend
Ideal para: Backend developers, ingenieros QA, cualquiera testeando microservicios Omite si: Solo necesitas testear sitios estáticos o frontends simples
Tus tests de frontend pasan. Los usuarios reportan que la app está rota. La API cambió, y nadie testeó el contrato.
API testing atrapa estos problemas antes de que lleguen a usuarios. Es más rápido que UI testing, más confiable, y testea la lógica de negocio real de la que depende tu aplicación.
He atrapado docenas de cambios rompientes en contratos de API — un campo renombrado, un status code cambiado, un header de paginación faltante. Cada uno habría causado downtime si no lo hubiera detectado un API test en CI.
Este tutorial enseña API testing desde cero — básicos de HTTP, convenciones REST, autenticación, manejo de errores, validación de esquemas y automatización.
¿Qué es API Testing?
API (Application Programming Interface) testing verifica que tus servicios backend funcionan correctamente. En lugar de hacer clic en un UI, envías requests HTTP directamente a endpoints y verificas respuestas.
Qué cubre API testing:
- Funcionalidad — ¿hace el endpoint lo que debería?
- Validación de datos — ¿están las respuestas estructuradas correctamente?
- Manejo de errores — ¿falla gracefully?
- Autenticación — ¿está el acceso controlado apropiadamente?
- Cumplimiento de esquema — ¿coincide la respuesta con el contrato?
- Performance — ¿puede manejar carga?
Por qué importa API testing:
- Más rápido que UI tests — sin renderizado de browser, milisegundos vs segundos
- Más estable — sin selectores flaky o problemas de timing
- Feedback más temprano — testea antes de que exista el frontend
- Mejor cobertura — testea edge cases imposibles via UI
Dónde encajan los API tests en la pirámide de testing:
/ UI Tests \ ← Lentos, caros, pocos
/ Integración \ ← API tests viven aquí
/ Unit Tests \ ← Rápidos, baratos, muchos
Los API tests son el punto ideal — suficientemente rápidos para correr en cada commit, pero suficientemente profundos para encontrar bugs de integración reales.
Fundamentos HTTP
Antes de testear APIs, entiende los básicos de HTTP.
Métodos HTTP
GET /users # Obtener todos los usuarios
GET /users/123 # Obtener usuario 123
POST /users # Crear nuevo usuario
PUT /users/123 # Reemplazar usuario 123
PATCH /users/123 # Actualizar partes de usuario 123
DELETE /users/123 # Eliminar usuario 123
| Método | Propósito | Tiene Body | Idempotente |
|---|---|---|---|
| GET | Leer datos | No | Sí |
| POST | Crear recurso | Sí | No |
| PUT | Reemplazar recurso | Sí | Sí |
| PATCH | Actualización parcial | Sí | No |
| DELETE | Eliminar recurso | Opcional | Sí |
La idempotencia importa para testing: Llamar GET o PUT 5 veces debería producir el mismo resultado que una vez. POST crea un nuevo recurso cada vez. Tus tests deben considerar esto — tests de PUT pueden reintentarse, tests de POST necesitan limpieza.
Códigos de Estado
2xx Éxito
├── 200 OK # Request exitoso
├── 201 Created # Recurso creado
├── 204 No Content # Éxito, nada que retornar
4xx Errores de Cliente
├── 400 Bad Request # Input inválido
├── 401 Unauthorized # Auth faltante/inválido
├── 403 Forbidden # Auth válido, sin permiso
├── 404 Not Found # Recurso no existe
├── 409 Conflict # Conflicta con estado actual
├── 422 Unprocessable # Validación falló
├── 429 Too Many Req # Rate limit excedido
5xx Errores de Servidor
├── 500 Internal Error # Bug del servidor
├── 502 Bad Gateway # Error upstream
├── 503 Unavailable # Servidor sobrecargado/mantenimiento
Error común: Solo verificar 200. Siempre verifica el código específico esperado — un 200 cuando esperabas 201 significa un problema.
Testing con Postman
Postman es la forma más fácil de empezar con API testing.
Primer Request
- Abre Postman
- Ingresa URL:
https://jsonplaceholder.typicode.com/posts/1 - Método: GET
- Click en Send
Agregando Tests
En Postman, agrega tests JavaScript en la pestaña “Tests”:
// Verificación de status code
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});
// Tiempo de respuesta
pm.test("Response time is less than 500ms", function () {
pm.expect(pm.response.responseTime).to.be.below(500);
});
// Validación de body
pm.test("Has correct structure", function () {
const json = pm.response.json();
pm.expect(json).to.have.property("id");
pm.expect(json).to.have.property("title");
pm.expect(json.id).to.eql(1);
});
Colecciones, variables y encadenamiento
// Variables de entorno
pm.environment.set("baseUrl", "https://api.example.com");
// Encadenar: extraer token de login, usar en siguiente request
pm.test("Save auth token", function () {
const response = pm.response.json();
pm.environment.set("token", response.token);
pm.environment.set("userId", response.user.id);
});
Ejecutar colecciones desde CLI con Newman:
npm install -g newman
newman run collection.json -e production.json --reporters cli,html
REST API Testing con Código
Python con requests + pytest
import requests
import pytest
BASE_URL = "https://api.example.com"
class TestUsersAPI:
def test_get_users_returns_list(self):
response = requests.get(f"{BASE_URL}/users")
assert response.status_code == 200
assert isinstance(response.json(), list)
assert len(response.json()) > 0
def test_create_user(self):
payload = {
"name": "John Doe",
"email": "john@example.com"
}
response = requests.post(
f"{BASE_URL}/users",
json=payload,
headers={"Content-Type": "application/json"}
)
assert response.status_code == 201
data = response.json()
assert data["name"] == payload["name"]
assert "id" in data
def test_get_nonexistent_user(self):
response = requests.get(f"{BASE_URL}/users/99999")
assert response.status_code == 404
def test_create_user_invalid_email(self):
payload = {"name": "John", "email": "not-an-email"}
response = requests.post(f"{BASE_URL}/users", json=payload)
assert response.status_code == 400
JavaScript con Supertest
const request = require('supertest');
const app = require('../src/app');
describe('Users API', () => {
test('GET /users returns list of users', async () => {
const response = await request(app)
.get('/users')
.expect(200)
.expect('Content-Type', /json/);
expect(Array.isArray(response.body)).toBe(true);
});
test('POST /users creates new user', async () => {
const newUser = { name: 'John Doe', email: 'john@example.com' };
const response = await request(app)
.post('/users')
.send(newUser)
.expect(201);
expect(response.body).toMatchObject(newUser);
expect(response.body.id).toBeDefined();
});
});
Java con REST Assured
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import org.junit.jupiter.api.*;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
public class UsersApiTest {
@BeforeAll
public static void setup() {
RestAssured.baseURI = "https://api.example.com";
}
@Test
public void getUsersReturnsList() {
given()
.when()
.get("/users")
.then()
.statusCode(200)
.contentType(ContentType.JSON)
.body("size()", greaterThan(0));
}
@Test
public void createUserReturnsCreated() {
String requestBody = """
{
"name": "John Doe",
"email": "john@example.com"
}
""";
given()
.contentType(ContentType.JSON)
.body(requestBody)
.when()
.post("/users")
.then()
.statusCode(201)
.body("name", equalTo("John Doe"))
.body("id", notNullValue());
}
}
Validación de Esquemas de Respuesta
Testear campos individuales no es suficiente. Valida toda la estructura para detectar drift de contrato.
JSON Schema con Python
from jsonschema import validate
user_schema = {
"type": "object",
"required": ["id", "name", "email", "createdAt"],
"properties": {
"id": {"type": "integer"},
"name": {"type": "string", "minLength": 1},
"email": {"type": "string", "format": "email"},
"createdAt": {"type": "string", "format": "date-time"},
"role": {"type": "string", "enum": ["admin", "user", "viewer"]}
},
"additionalProperties": False
}
def test_user_response_matches_schema():
response = requests.get(f"{BASE_URL}/users/1")
validate(instance=response.json(), schema=user_schema)
Por qué importa la validación de esquema: Un developer agrega un campo, renombra otro o cambia un tipo. Las verificaciones puntuales lo pierden. La validación de esquema detecta cada cambio estructural — es el guardián de tu contrato API.
Testing de Autenticación
Bearer Token (JWT)
# Paso 1: Login para obtener token
login_response = requests.post(
"https://api.example.com/auth/login",
json={"email": "user@example.com", "password": "secret"}
)
token = login_response.json()["token"]
# Paso 2: Usar token en requests
response = requests.get(
"https://api.example.com/protected",
headers={"Authorization": f"Bearer {token}"}
)
Testing de Escenarios de Auth
class TestAuthentication:
def test_protected_endpoint_requires_auth(self):
response = requests.get(f"{BASE_URL}/protected")
assert response.status_code == 401
def test_invalid_token_rejected(self):
response = requests.get(
f"{BASE_URL}/protected",
headers={"Authorization": "Bearer invalid_token"}
)
assert response.status_code == 401
def test_valid_token_grants_access(self):
token = get_valid_token()
response = requests.get(
f"{BASE_URL}/protected",
headers={"Authorization": f"Bearer {token}"}
)
assert response.status_code == 200
def test_insufficient_permissions(self):
viewer_token = get_token_for_role("viewer")
response = requests.delete(
f"{BASE_URL}/users/1",
headers={"Authorization": f"Bearer {viewer_token}"}
)
assert response.status_code == 403
Testing GraphQL
GraphQL usa un único endpoint con queries y mutations. El testing es fundamentalmente diferente de REST.
def test_graphql_query():
query = """
query GetUser($id: ID!) {
user(id: $id) { id, name, email }
}
"""
response = requests.post(
f"{BASE_URL}/graphql",
json={"query": query, "variables": {"id": "123"}}
)
assert response.status_code == 200
data = response.json()
assert "errors" not in data
assert data["data"]["user"]["id"] == "123"
def test_graphql_invalid_query():
"""GraphQL retorna 200 con array errors, no 400"""
response = requests.post(
f"{BASE_URL}/graphql",
json={"query": "{ nonExistentField }"}
)
assert response.status_code == 200
assert "errors" in response.json()
Diferencia clave con REST: GraphQL siempre retorna 200 para requests HTTP válidos. Los errores aparecen en el array errors dentro del cuerpo de respuesta.
Testing de Errores
Testea cómo tu API maneja problemas. Aquí vive la mayoría de bugs.
class TestErrorHandling:
def test_malformed_json_returns_400(self):
response = requests.post(
f"{BASE_URL}/users",
data="not valid json",
headers={"Content-Type": "application/json"}
)
assert response.status_code == 400
def test_missing_required_field_returns_400(self):
response = requests.post(
f"{BASE_URL}/users",
json={"name": "John"} # falta email
)
assert response.status_code == 400
def test_duplicate_email_returns_409(self):
requests.post(f"{BASE_URL}/users", json={
"name": "John", "email": "john@example.com"
})
response = requests.post(f"{BASE_URL}/users", json={
"name": "Jane", "email": "john@example.com"
})
assert response.status_code == 409
Testing de Rate Limiting
La mayoría de APIs en producción tienen límites de velocidad. Testéalos.
def test_rate_limiting():
response = requests.get(f"{BASE_URL}/users")
assert "X-RateLimit-Limit" in response.headers
assert "X-RateLimit-Remaining" in response.headers
def test_rate_limit_exceeded():
for _ in range(110): # Asumiendo límite de 100 req/min
requests.get(f"{BASE_URL}/users")
response = requests.get(f"{BASE_URL}/users")
assert response.status_code == 429
assert "Retry-After" in response.headers
Performance Testing
Load Testing con k6
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '30s', target: 20 },
{ duration: '1m', target: 20 },
{ duration: '10s', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<500'],
http_req_failed: ['rate<0.01'],
},
};
export default function () {
const response = http.get('https://api.example.com/users');
check(response, {
'status is 200': (r) => r.status === 200,
'response time OK': (r) => r.timings.duration < 500,
});
sleep(1);
}
Integración CI/CD
name: API Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: '3.12' }
- run: pip install pytest requests jsonschema
- run: pytest tests/api/ -v --tb=short
- run: |
npm install -g newman
newman run collection.json -e environment.json
IA en API Testing
Las herramientas de IA aceleran significativamente el desarrollo de tests de API en 2026.
Lo que la IA hace bien:
- Generar casos de test desde specs OpenAPI/Swagger — pega la spec, obtén 50+ tests
- Crear datos de test válidos e inválidos para testing de límites
- Escribir boilerplate para autenticación y operaciones CRUD
- Convertir entre frameworks (scripts Postman a pytest, REST Assured a Supertest)
Lo que aún necesita humanos:
- Entender requisitos de negocio y restricciones de dominio
- Diseñar estrategia de testing (¿qué endpoints son críticos?)
- Debuggear tests flaky por dependencias de datos
- Interpretar resultados de performance
Prompt útil:
Genera test cases en pytest para POST /api/orders con body { customerId, items: [{productId, quantity}], couponCode? }. Cubre: orden válida, array items vacío, customerId inválido, cantidad negativa, cupón inválido. Incluye validación de JSON Schema.
FAQ
¿Qué es el testing de API?
API testing verifica que las APIs funcionan correctamente enviando requests HTTP y validando respuestas. Testea funcionalidad, validación de datos, manejo de errores, autenticación y performance. A diferencia de UI testing, API testing prueba directamente la capa de lógica de negocio — un test de API típico tarda milisegundos vs segundos para un test de browser.
¿Qué herramientas se usan para API testing?
Herramientas populares incluyen:
- Postman — herramienta GUI para testing manual y automatización, ideal para aprender
- REST Assured — librería Java con sintaxis BDD fluida
- Supertest — Node.js/JavaScript API testing, integración con Jest
- requests + pytest — Python API testing, máxima flexibilidad
- k6 — Performance y load testing con JavaScript
- Newman — CLI runner para colecciones Postman en CI/CD
- Karate — framework BDD combinando API y performance testing
¿Cuál es la diferencia entre API testing y unit testing?
Unit tests verifican funciones individuales aisladas, mockeando todas las dependencias. API tests verifican endpoints HTTP completos, incluyendo routing, middleware, autenticación, operaciones de BD y formateo de respuestas. API tests son tests de integración que verifican que los componentes funcionan juntos. Se necesitan ambos: unit tests para bugs lógicos, API tests para bugs de integración.
¿Cómo testeo APIs autenticadas?
- Envía request de login con credenciales
- Extrae token de la respuesta
- Incluye token en header Authorization para requests siguientes
- Guarda token en variable de entorno para reusar
- Implementa refresh de token para tokens que expiran
- Testea ambos escenarios — autenticado y no autenticado
- Testea acceso basado en roles — viewer no puede borrar, admin sí
¿Cómo difiere el testing de REST API del de GraphQL?
REST usa múltiples endpoints (GET /users, POST /users) con estructura de respuesta fija. GraphQL usa un endpoint (/graphql) donde el cliente pide campos específicos. Diferencias clave: GraphQL retorna 200 incluso con errores (verifica el array errors), necesitas testear límites de profundidad de queries (prevención de DoS), y validar que los resolvers no crean N+1 queries a la BD.
¿Cuántos tests de API necesito?
Por endpoint: 1 test happy path, 2-3 tests negativos (400, 401, 404), 1 test de validación de esquema y 1 test de auth. Un recurso CRUD típico (5 endpoints) necesita 15-20 tests. Para una API con 20 recursos — 300-400 tests. Empieza por endpoints críticos de negocio — login, pagos, datos principales — luego expande cobertura.
Recursos Oficiales
Ver También
- Postman Tutorial - Guía completa de API testing con Postman
- REST Assured Tutorial - Java API testing con REST Assured
- GraphQL Testing Guide - Testing de APIs GraphQL
- API Performance Testing - Load y stress testing de APIs
- Contract Testing con Pact - Consumer-driven contract testing
- API Security Testing - OWASP API Security Top 10
- Karate API Testing - Automatización API estilo BDD
- Comparación de Herramientas API - Postman vs REST Assured vs alternativas
- gRPC API Testing - Testing de servicios gRPC
- Tutorial de Automatización - Fundamentos de automatización
