📋 SOBRE ESTA GUÍA
Esta guía te ayudará a probar y validar que tu proyecto funciona correctamente.
Incluye:
- ✅ Pruebas detalladas paso a paso
- ✅ Ejemplos de solicitudes HTTP (Postman/cURL)
- ✅ Respuestas esperadas vs errores comunes
- ✅ Casos de prueba interesantes y realistas
- ✅ Validación de seguridad y autenticación
✅ CHECKLIST PRELIMINAR
Antes de empezar las pruebas, verifica:
| ✓ | Requisito | Cómo verificar |
|---|---|---|
| ☐ | Servidor Django corriendo | python manage.py runserver |
| ☐ | Base de datos MySQL configurada | python manage.py check |
| ☐ | Migraciones aplicadas | python manage.py migrate |
| ☐ | Google OAuth configurado | Credenciales en settings.py |
| ☐ | Datos de prueba en BD | python manage.py loaddata o crear manualmente |
| ☐ | Postman instalado (opcional) | O usar cURL en terminal |
🔐 PARTE 1: LOGIN CON GOOGLE (OAuth 2.0)
🎯 OBJETIVO DE LA PRUEBA
Verificar que el flujo completo de autenticación con Google OAuth funciona correctamente:
- Usuario solicita login con Google
- Redirección a pantalla de Google
- Usuario autoriza permisos
- Google retorna código de autorización
- Backend intercambia código por token
- Backend genera JWT propio
- Usuario recibe tokens y puede acceder a la API
1PRUEBA: Flujo completo de login
1Abrir la página de login
http://127.0.0.1:8000/oauth/login/
🖼️ Deberías ver:
Botón grande: "🔐 Iniciar Sesión con Google"
Indicador: "Cargando..." (animado)
Estilo: Gradiente azul moderno
2Hacer clic en "Iniciar Sesión con Google"
✅ COMPORTAMIENTO ESPERADO:
- La página te redirige automáticamente a Google
- Ves la pantalla de selección de cuenta de Google
- Google te muestra qué permisos solicita la app
❌ ERRORES COMUNES:
| Error | Causa | Solución |
|---|---|---|
| redirect_uri_mismatch | URI no registrada en Google Console | Agregar http://127.0.0.1:8000/api/auth/google/callback/ |
| Invalid client_id | Credenciales incorrectas | Verificar CLIENT_ID en settings.py |
| Página no carga | Servidor no corriendo | python manage.py runserver |
3Seleccionar cuenta de Google y autorizar
✅ RESPUESTA EXITOSA:
Después de autorizar, deberías ver:
✅ Login Exitoso
Email: tu.email@gmail.com
Nombre: Tu Nombre
Token: eyJ0eXAiOiJKV1QiLCJhbGc...
Estado: Token guardado en localStorage
Botón: 🏠 Ir al Inicio
4Verificar token en navegador
Abre la consola del navegador (F12) y ejecuta:
// Ver token de acceso
console.log(localStorage.getItem('access_token'));
// Ver token de refresco
console.log(localStorage.getItem('refresh_token'));
// Deberías ver tokens JWT largos (eyJ...)
5Decodificar el JWT (opcional)
Ve a https://jwt.io y pega tu token. Deberías ver:
{
"token_type": "access",
"exp": 1735689600,
"iat": 1735686000,
"jti": "abc123...",
"user_id": 1,
"username": "tu.email@gmail.com"
}
2PRUEBA: Usar token OAuth para acceder a API
Método 1: Con Postman
1Crear nueva request en Postman
- Método: GET
- URL:
http://127.0.0.1:8000/api/libros/
2Agregar token en Headers
Authorization: Bearer TU_TOKEN_AQUI
3Enviar request
✅ RESPUESTA ESPERADA (200 OK):
{
"count": 15,
"next": "http://127.0.0.1:8000/api/libros/?page=2",
"previous": null,
"results": [
{
"id": 1,
"titulo": "Cien Años de Soledad",
"autor": "Gabriel García Márquez",
"isbn": "978-0307474728",
"fecha_publicacion": "1967-05-30",
"stock": 5,
"esta_disponible": true,
"prestamos_activos": 2
},
// ... más libros
]
}
Método 2: Con cURL (Terminal)
curl -H "Authorization: Bearer TU_TOKEN" \
http://127.0.0.1:8000/api/libros/
💡 EJEMPLO INTERESANTE: Test User en Google
Para probar sin esperar aprobación de Google:
- Ve a Google Cloud Console
- OAuth consent screen → Test users
- Agrega tu email como "test user"
- Ahora puedes loguearte sin restricciones
Nota: En modo testing, solo usuarios agregados pueden autenticarse
🔑 PARTE 2: LOGIN CON JWT (Tradicional)
🎯 OBJETIVO DE LA PRUEBA
Verificar que el login tradicional con usuario/contraseña funciona y genera tokens JWT válidos.
1PRUEBA: Obtener token JWT
1Crear usuario de prueba (si no existe)
python manage.py createsuperuser
# O crear usuario normal:
python manage.py shell
>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('testuser', 'test@test.com', 'password123')
>>> user.save()
2Solicitar token con Postman
Configuración:
- Método: POST
- URL:
http://127.0.0.1:8000/api/auth/login/ - Body: raw → JSON
{
"username": "testuser",
"password": "password123"
}
✅ RESPUESTA ESPERADA (200 OK):
{
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTczNTc3NTQwMCwiaWF0IjoxNzM1Njg5MDAwLCJqdGkiOiJhYmMxMjMuLi4iLCJ1c2VyX2lkIjoxfQ...",
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzM1NjkyNjAwLCJpYXQiOjE3MzU2ODkwMDAsImp0aSI6InhlZDQ1Ni4uLiIsInVzZXJfaWQiOjF9..."
}
❌ ERRORES COMUNES:
| Error | Respuesta | Solución |
|---|---|---|
| 401 Unauthorized | "No active account found with the given credentials" | Usuario o contraseña incorrectos |
| 400 Bad Request | "This field is required" | Falta username o password en body |
| 405 Method Not Allowed | "Method GET not allowed" | Usar POST, no GET |
3Con cURL
curl -X POST http://127.0.0.1:8000/api/auth/login/ \
-H "Content-Type: application/json" \
-d '{
"username": "testuser",
"password": "password123"
}'
2PRUEBA: Usar token JWT para acceder a API
1Copiar el token "access" de la respuesta anterior
2Hacer request a API protegida
Con Postman:
- Método: GET
- URL:
http://127.0.0.1:8000/api/libros/ - Headers:
Authorization: Bearer TU_ACCESS_TOKEN
Con cURL:
curl -H "Authorization: Bearer eyJ0eXAiOiJKV1Q..." \
http://127.0.0.1:8000/api/libros/
✅ RESPUESTA ESPERADA (200 OK):
Lista de libros (igual que con OAuth)
3PRUEBA: Refrescar token JWT expirado
📚 CONTEXTO:
Los tokens JWT tienen tiempo de expiración:
- Access Token: Expira en 1 hora
- Refresh Token: Expira en 1 día
Cuando el access token expira, usa el refresh token para obtener uno nuevo sin pedir contraseña.
1Solicitar nuevo access token
Con Postman:
- Método: POST
- URL:
http://127.0.0.1:8000/api/auth/token/refresh/ - Body (JSON):
{
"refresh": "TU_REFRESH_TOKEN_AQUI"
}
✅ RESPUESTA ESPERADA (200 OK):
{
"access": "eyJ0eXAiOiJKV1QiLCJhbGc... (NUEVO TOKEN)"
}
Ahora puedes usar este nuevo access token por otra hora más.
💡 EJEMPLO INTERESANTE: Script Python para auto-renovar tokens
Crea un archivo auto_refresh.py:
import requests
import time
from datetime import datetime, timedelta
class JWTClient:
def __init__(self, username, password):
self.base_url = 'http://127.0.0.1:8000'
self.access_token = None
self.refresh_token = None
self.expires_at = None
# Login inicial
self.login(username, password)
def login(self, username, password):
"""Obtener tokens iniciales"""
response = requests.post(
f'{self.base_url}/api/auth/login/',
json={'username': username, 'password': password}
)
data = response.json()
self.access_token = data['access']
self.refresh_token = data['refresh']
self.expires_at = datetime.now() + timedelta(minutes=55) # 5 min antes
print("✅ Login exitoso!")
def refresh_access_token(self):
"""Refrescar access token"""
if datetime.now() >= self.expires_at:
print("🔄 Refrescando token...")
response = requests.post(
f'{self.base_url}/api/auth/token/refresh/',
json={'refresh': self.refresh_token}
)
data = response.json()
self.access_token = data['access']
self.expires_at = datetime.now() + timedelta(minutes=55)
print("✅ Token refrescado!")
def get_libros(self):
"""Obtener libros (auto-refresca si es necesario)"""
self.refresh_access_token()
response = requests.get(
f'{self.base_url}/api/libros/',
headers={'Authorization': f'Bearer {self.access_token}'}
)
return response.json()
# Uso:
client = JWTClient('testuser', 'password123')
# Puedes usar el cliente por horas sin volver a loguearte
libros = client.get_libros()
print(f"📚 {libros['count']} libros encontrados")
# Esperar 1 hora (el script automáticamente refresca el token)
time.sleep(3600)
libros = client.get_libros() # ¡Sigue funcionando!
📚 PARTE 3: EXPLORAR API REST
🎯 OBJETIVO DE LA PRUEBA
Explorar todas las operaciones CRUD y funcionalidades avanzadas de la API.
1PRUEBA: Listar todos los libros (GET)
Request básico:
GET http://127.0.0.1:8000/api/libros/
Authorization: Bearer TU_TOKEN
✅ RESPUESTA:
{
"count": 25,
"next": "http://127.0.0.1:8000/api/libros/?page=2",
"previous": null,
"results": [/* 10 libros por página */]
}
2PRUEBA: Filtrar libros (Query Parameters)
Ejemplo 1: Buscar por autor
GET http://127.0.0.1:8000/api/libros/?autor=García
Authorization: Bearer TU_TOKEN
Ejemplo 2: Libros disponibles
GET http://127.0.0.1:8000/api/libros/?esta_disponible=true
Ejemplo 3: Ordenar por fecha
GET http://127.0.0.1:8000/api/libros/?ordering=-fecha_publicacion
El "-" ordena descendente (más reciente primero)
Ejemplo 4: Buscar en título
GET http://127.0.0.1:8000/api/libros/?search=quijote
Ejemplo 5: Combinar múltiples filtros
GET http://127.0.0.1:8000/api/libros/?autor=García&esta_disponible=true&ordering=titulo
3PRUEBA: Ver detalle de un libro (GET)
GET http://127.0.0.1:8000/api/libros/1/
Authorization: Bearer TU_TOKEN
✅ RESPUESTA:
{
"id": 1,
"titulo": "Cien Años de Soledad",
"autor": "Gabriel García Márquez",
"isbn": "978-0307474728",
"fecha_publicacion": "1967-05-30",
"descripcion": "La historia de la familia Buendía...",
"editorial": "Editorial Sudamericana",
"genero": "Realismo mágico",
"idioma": "Español",
"paginas": 471,
"stock": 5,
"precio": 299.00,
"esta_disponible": true,
"prestamos_activos": 2,
"fecha_registro": "2025-01-15T10:30:00Z",
"ultima_actualizacion": "2025-02-01T14:20:00Z"
}
4PRUEBA: Crear nuevo libro (POST)
⚠️ PERMISOS NECESARIOS:
Para crear libros necesitas ser admin o tener permisos específicos.
Request:
POST http://127.0.0.1:8000/api/libros/
Authorization: Bearer TU_TOKEN
Content-Type: application/json
{
"titulo": "El Código Da Vinci",
"autor": "Dan Brown",
"isbn": "978-0307474278",
"fecha_publicacion": "2003-03-18",
"descripcion": "Un thriller sobre secretos del cristianismo",
"editorial": "Doubleday",
"genero": "Thriller",
"idioma": "Español",
"paginas": 592,
"stock": 10,
"precio": 399.00
}
✅ RESPUESTA (201 Created):
{
"id": 26,
"titulo": "El Código Da Vinci",
"autor": "Dan Brown",
...
"fecha_registro": "2025-02-21T02:15:00Z"
}
5PRUEBA: Actualizar libro (PUT/PATCH)
Actualización completa (PUT):
PUT http://127.0.0.1:8000/api/libros/26/
Authorization: Bearer TU_TOKEN
Content-Type: application/json
{
"titulo": "El Código Da Vinci",
"autor": "Dan Brown",
"isbn": "978-0307474278",
"fecha_publicacion": "2003-03-18",
"stock": 15, // Actualizado
"precio": 349.00 // Actualizado
// ... todos los campos requeridos
}
Actualización parcial (PATCH) - RECOMENDADO:
PATCH http://127.0.0.1:8000/api/libros/26/
Authorization: Bearer TU_TOKEN
Content-Type: application/json
{
"stock": 15,
"precio": 349.00
}
// Solo envías los campos que quieres cambiar
6PRUEBA: Eliminar libro (DELETE)
DELETE http://127.0.0.1:8000/api/libros/26/
Authorization: Bearer TU_TOKEN
✅ RESPUESTA (204 No Content):
Sin body. El status code 204 indica éxito.
💡 EJEMPLOS INTERESANTES: Casos de uso reales
1️⃣ Sistema de búsqueda avanzada
// Buscar libros de ciencia ficción disponibles, ordenados por popularidad
GET /api/libros/?genero=ciencia+ficcion&esta_disponible=true&ordering=-prestamos_activos
// Buscar libros publicados en los últimos 5 años
GET /api/libros/?fecha_publicacion__gte=2021-01-01
// Buscar libros con más de 10 copias en stock
GET /api/libros/?stock__gte=10
2️⃣ Dashboard de administrador
// Libros con bajo stock (< 3)
GET /api/libros/?stock__lt=3
// Libros sin préstamos activos
GET /api/libros/?prestamos_activos=0
// Top 10 libros más prestados
GET /api/libros/?ordering=-prestamos_activos&page_size=10
3️⃣ Sistema de recomendaciones
// Libros del mismo autor
GET /api/libros/?autor=Gabriel+García+Márquez
// Libros del mismo género
GET /api/libros/?genero=Realismo+mágico
// Libros similares por idioma y año
GET /api/libros/?idioma=Español&fecha_publicacion__gte=1960&fecha_publicacion__lte=1970
4️⃣ Reportes y estadísticas
// Total de libros
GET /api/libros/?page_size=1 // Ver el "count" en la respuesta
// Libros por año
GET /api/libros/?fecha_publicacion__year=2024
// Valor total del inventario (necesitas sumar en frontend)
GET /api/libros/?fields=stock,precio
7PRUEBA: Paginación personalizada
Cambiar tamaño de página:
// Ver 25 libros por página
GET /api/libros/?page_size=25
// Ver solo 5
GET /api/libros/?page_size=5
// Ir a página específica
GET /api/libros/?page=3
Navegar por resultados:
// Respuesta incluye enlaces de navegación:
{
"count": 100,
"next": "http://127.0.0.1:8000/api/libros/?page=2",
"previous": null,
"results": [...]
}
// Usar "next" y "previous" para navegar
8PRUEBA: Endpoints adicionales (si los implementaste)
Préstamos:
// Crear préstamo
POST /api/prestamos/
{
"libro_id": 1,
"usuario_id": 5,
"fecha_devolucion_esperada": "2025-03-01"
}
// Ver préstamos activos
GET /api/prestamos/?estado=activo
// Devolver libro
PATCH /api/prestamos/1/devolver/
Categorías:
// Listar categorías
GET /api/categorias/
// Libros por categoría
GET /api/categorias/1/libros/
Usuarios:
// Ver perfil
GET /api/users/me/
// Actualizar perfil
PATCH /api/users/me/
{
"first_name": "Juan",
"last_name": "Pérez"
}
// Historial de préstamos
GET /api/users/me/prestamos/
🚀 CASOS DE PRUEBA AVANZADOS
🔒 Pruebas de Seguridad
Test 1: Acceso sin token
GET /api/libros/
// Sin header Authorization
❌ Esperado: 401 Unauthorized
{
"detail": "Authentication credentials were not provided."
}
Test 2: Token inválido
GET /api/libros/
Authorization: Bearer token_invalido_123
❌ Esperado: 401 Unauthorized
{
"detail": "Given token not valid for any token type",
"code": "token_not_valid"
}
Test 3: Token expirado
// Usar token viejo (> 1 hora)
GET /api/libros/
Authorization: Bearer TOKEN_EXPIRADO
❌ Esperado: 401 Unauthorized
{
"detail": "Token is expired",
"code": "token_not_valid"
}
Test 4: Acceso sin permisos
// Usuario normal intentando eliminar
DELETE /api/libros/1/
Authorization: Bearer TOKEN_USUARIO_NORMAL
❌ Esperado: 403 Forbidden
{
"detail": "You do not have permission to perform this action."
}
⚡ Pruebas de Rendimiento
Test 1: Carga de datos masiva
// Solicitar muchos libros de una vez
GET /api/libros/?page_size=100
✅ Debería responder en < 2 segundos
Test 2: Búsqueda compleja
GET /api/libros/?search=garcia&genero=novela&ordering=titulo
✅ Debería usar índices de BD eficientemente
Test 3: Crear múltiples libros
Script Python para prueba de carga:
import requests
import time
token = "TU_TOKEN"
headers = {'Authorization': f'Bearer {token}'}
start = time.time()
for i in range(100):
requests.post('http://127.0.0.1:8000/api/libros/',
headers=headers,
json={
'titulo': f'Libro Test {i}',
'autor': f'Autor {i}',
'isbn': f'978-030747{i:04d}',
'fecha_publicacion': '2025-01-01',
'stock': 10,
'precio': 299.00
})
end = time.time()
print(f"⏱️ Tiempo: {end - start:.2f}s para 100 libros")
print(f"📊 Promedio: {(end - start)/100:.3f}s por libro")
🔄 Pruebas de Integridad
Test 1: Validación de datos
// Intentar crear libro sin campos requeridos
POST /api/libros/
{
"titulo": "Solo título"
}
❌ Esperado: 400 Bad Request
{
"autor": ["This field is required."],
"isbn": ["This field is required."],
"fecha_publicacion": ["This field is required."]
}
Test 2: ISBN duplicado
// Crear libro con ISBN existente
POST /api/libros/
{
"isbn": "978-0307474728", // Ya existe
...
}
❌ Esperado: 400 Bad Request
{
"isbn": ["Libro with this isbn already exists."]
}
Test 3: Fecha inválida
POST /api/libros/
{
"fecha_publicacion": "2030-12-31", // Fecha futura
...
}
❌ Esperado: 400 Bad Request
{
"fecha_publicacion": ["La fecha de publicación no puede ser futura."]
}
Test 4: Stock negativo
PATCH /api/libros/1/
{
"stock": -5
}
❌ Esperado: 400 Bad Request
{
"stock": ["El stock no puede ser negativo."]
}
🛠️ HERRAMIENTAS RECOMENDADAS
1. Postman (GUI) - RECOMENDADO
Ventajas:
- ✅ Interfaz visual intuitiva
- ✅ Guarda colecciones de requests
- ✅ Variables de entorno (tokens, URLs)
- ✅ Tests automatizados
- ✅ Generación de código
Configuración rápida:
- Descargar de
https://www.postman.com/downloads/ - Crear nueva colección: "Biblioteca API"
- Crear variable de entorno:
BASE_URL = http://127.0.0.1:8000 - Crear variable:
TOKEN = TU_TOKEN - Usar en requests:
{{BASE_URL}}/api/libros/
2. cURL (Terminal)
Ventajas:
- ✅ Ya instalado en Linux/Mac
- ✅ Scripts automatizables
- ✅ Ligero y rápido
Comandos útiles:
# GET con formato bonito
curl -H "Authorization: Bearer TOKEN" \
http://127.0.0.1:8000/api/libros/ | jq
# POST con archivo JSON
curl -X POST \
-H "Authorization: Bearer TOKEN" \
-H "Content-Type: application/json" \
-d @libro.json \
http://127.0.0.1:8000/api/libros/
# Ver headers de respuesta
curl -i -H "Authorization: Bearer TOKEN" \
http://127.0.0.1:8000/api/libros/
3. HTTPie (Terminal) - Alternativa moderna
Instalación:
pip install httpie
Sintaxis más amigable:
# GET
http GET :8000/api/libros/ "Authorization: Bearer TOKEN"
# POST
http POST :8000/api/libros/ \
Authorization:"Bearer TOKEN" \
titulo="Nuevo Libro" \
autor="Autor Test" \
isbn="978-1234567890"
# PATCH
http PATCH :8000/api/libros/1/ \
Authorization:"Bearer TOKEN" \
stock:=15
4. Django REST Framework Browser (Incluido)
Acceso:
http://127.0.0.1:8000/api/libros/
Ventajas:
- ✅ Ya incluido, sin instalar nada
- ✅ Interfaz web interactiva
- ✅ Formularios para POST/PUT
- ✅ Botones de login
- ✅ Documentación automática
💡 TIP: Login en el navegador
1. Ve a http://127.0.0.1:8000/admin/
2. Loguéate con tu superusuario
3. Ahora puedes usar la API desde el navegador
✅ CHECKLIST FINAL DE PRUEBAS
Verifica que completaste:
| ✓ | Prueba | Estado |
|---|---|---|
| ☐ | Login con Google OAuth funciona | Pendiente |
| ☐ | Tokens se guardan en localStorage | Pendiente |
| ☐ | Login con JWT (usuario/contraseña) | Pendiente |
| ☐ | Refresh token funciona | Pendiente |
| ☐ | GET /api/libros/ retorna datos | Pendiente |
| ☐ | Filtros y búsqueda funcionan | Pendiente |
| ☐ | POST crea nuevo libro | Pendiente |
| ☐ | PATCH actualiza libro | Pendiente |
| ☐ | DELETE elimina libro | Pendiente |
| ☐ | Paginación funciona correctamente | Pendiente |
| ☐ | Seguridad: Sin token = 401 | Pendiente |
| ☐ | Seguridad: Token inválido = 401 | Pendiente |
| ☐ | Validaciones de datos funcionan | Pendiente |
| ☐ | Permisos: Solo admin puede DELETE | Pendiente |