Bases de Datos NoSQL en Stacks Modernos

Las bases de datos NoSQL intercambian el schema rígido y las garantías ACID de SQL por flexibilidad, escalabilidad y rendimiento en casos de uso específicos. Como ingeniero QA, necesitas enfoques de testing diferentes para cada tipo.

TipoEjemplosCaso de UsoFoco del Testing
DocumentoMongoDB, CouchDBSchemas flexibles, datos anidadosConsistencia de schema, indexación
Key-ValueRedis, MemcachedCaching, sesiones, contadoresTTL, eviction, tipos de datos
Wide-ColumnDynamoDB, CassandraAlta escala, time-seriesEstrategia de partición, consistencia
GraphNeo4j, NeptuneRelaciones, redesCorrectitud de traversal

Testing de MongoDB

MongoDB almacena datos como documentos JSON-like (BSON). Las colecciones no aplican schema por defecto, lo que significa que tu aplicación — y tus tests — deben validar la estructura de datos.

Testing de Validación de Schema

db.createCollection("users", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["name", "email"],
      properties: {
        name: { bsonType: "string", minLength: 1 },
        email: { bsonType: "string", pattern: "^.+@.+\\..+$" },
        age: { bsonType: "int", minimum: 0, maximum: 150 }
      }
    }
  }
});

Casos de prueba:

// Documento válido — debe tener éxito
db.users.insertOne({ name: "Alice", email: "alice@test.com", age: 30 });

// Campo requerido faltante — debe fallar
db.users.insertOne({ name: "Bob" });

// Tipo inválido — debe fallar
db.users.insertOne({ name: "Charlie", email: "charlie@test.com", age: "thirty" });

Testing de Queries

const result = db.orders.aggregate([
  { $match: { status: "completed" } },
  { $group: { _id: "$userId", totalSpent: { $sum: "$total" } } },
  { $sort: { totalSpent: -1 } },
  { $limit: 10 }
]);

Testing de Índices

db.users.createIndex({ email: 1 }, { unique: true });
db.users.find({ email: "alice@test.com" }).explain("executionStats");
// Busca stage "IXSCAN" (no "COLLSCAN")

Testing de Redis

Redis es un almacén key-value en memoria usado para caching, sesiones, rate limiting y funcionalidades en tiempo real.

Testing de Tipos de Datos

# String
SET user:123:name "Alice"
GET user:123:name

# Hash
HSET user:123 name "Alice" email "alice@test.com"
HGETALL user:123

# List
LPUSH notifications:123 "Nuevo pedido" "Pago recibido"
LRANGE notifications:123 0 -1

# Set
SADD user:123:roles "admin" "editor" "admin"
SMEMBERS user:123:roles  # {"admin", "editor"} — sin duplicados

# Sorted Set
ZADD leaderboard 100 "Alice" 200 "Bob" 150 "Charlie"
ZREVRANGE leaderboard 0 2 WITHSCORES

Testing de TTL

SET session:abc123 "user-data" EX 60
TTL session:abc123  # Retorna segundos restantes
EXISTS session:abc123  # 1 (existe)
# Después de 60 segundos...
EXISTS session:abc123  # 0 (expirado)

Testing de Invalidación de Cache

  1. Cache hit: Datos en Redis, app retorna valor cacheado.
  2. Cache miss: Datos no en Redis, app consulta BD y cachea resultado.
  3. Cache invalidation: Datos actualizados en BD, valor cacheado invalidado.
  4. Stale cache: Después de invalidación, siguiente solicitud retorna datos frescos.

Testing de DynamoDB

DynamoDB es un wide-column store completamente gestionado de AWS.

Testing de Diseño de Keys

import boto3

dynamodb = boto3.resource('dynamodb', endpoint_url='http://localhost:8000')
table = dynamodb.Table('Orders')

table.put_item(Item={
    'userId': 'user-123',
    'orderId': 'order-456',
    'total': 99.99,
    'status': 'pending'
})

response = table.query(
    KeyConditionExpression='userId = :uid',
    ExpressionAttributeValues={':uid': 'user-123'}
)
assert len(response['Items']) >= 1

Ejercicio: Laboratorio de Testing NoSQL

Parte 1: Testing de MongoDB

docker run -d --name mongo-test -p 27017:27017 mongo:7

Tarea 1.1: Crea una colección con validación de schema para “products”. Prueba que documentos inválidos sean rechazados.

Tarea 1.2: Inserta 1,000 productos con varias categorías. Escribe queries de aggregation y verifica resultados.

Tarea 1.3: Crea un índice compuesto en {category: 1, price: -1}. Verifica con explain() que los queries usen el índice.

Parte 2: Testing de Redis

docker run -d --name redis-test -p 6379:6379 redis:7

Tarea 2.1: Implementa y prueba un session store con TTL de 300 segundos.

Tarea 2.2: Implementa y prueba un rate limiter: 10 solicitudes por minuto por usuario.

Tarea 2.3: Prueba invalidación de cache: cachea perfil, actualiza “BD”, invalida cache, verifica que próxima lectura traiga datos frescos.

Parte 3: Testing de DynamoDB

docker run -d --name dynamo-test -p 8000:8000 amazon/dynamodb-local

Tarea 3.1: Crea tabla Orders con userId (partition key) y orderId (sort key). Inserta 50 pedidos y prueba patrones de query.

Tarea 3.2: Prueba conditional writes — actualiza estado solo si es “pending”.

Entregables

  1. MongoDB: Tests de validación, verificación de aggregation, prueba de uso de índices.
  2. Redis: Tests de TTL, rate limiter, invalidación de cache.
  3. DynamoDB: Tests de patrones de query, conditional writes.
  4. Resumen comparativo de diferencias entre testing SQL y NoSQL.