← Volver a Guía Principal

🧪 GUÍA DE PRUEBAS FUNCIONALES

🔐 Login Google 🔑 Login JWT 📚 API REST

Pruebas paso a paso con ejemplos reales e interesantes

Universidad Tecnológica de Hermosillo | Profesor: Bernardo Prado

📋 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:

  1. Usuario solicita login con Google
  2. Redirección a pantalla de Google
  3. Usuario autoriza permisos
  4. Google retorna código de autorización
  5. Backend intercambia código por token
  6. Backend genera JWT propio
  7. 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:

  1. La página te redirige automáticamente a Google
  2. Ves la pantalla de selección de cuenta de Google
  3. 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:

  1. Ve a Google Cloud Console
  2. OAuth consent screen → Test users
  3. Agrega tu email como "test user"
  4. 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:

  1. Descargar de https://www.postman.com/downloads/
  2. Crear nueva colección: "Biblioteca API"
  3. Crear variable de entorno: BASE_URL = http://127.0.0.1:8000
  4. Crear variable: TOKEN = TU_TOKEN
  5. 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