← 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