NoSQL-базы в современных стеках

NoSQL-базы обменивают жёсткую схему и ACID-гарантии SQL на гибкость, масштабируемость и производительность в конкретных случаях. Как QA-инженеру вам нужны разные подходы к тестированию для каждого типа.

ТипПримерыСлучай использованияФокус тестирования
ДокументноеMongoDB, CouchDBГибкие схемы, вложенные данныеСогласованность схемы, индексация
Key-ValueRedis, MemcachedКеширование, сессии, счётчикиTTL, вытеснение, типы данных
Wide-ColumnDynamoDB, CassandraВысокая масштабируемость, time-seriesСтратегия партиционирования, согласованность
ГрафовоеNeo4j, NeptuneСвязи, сетиКорректность обходов

Тестирование MongoDB

MongoDB хранит данные как JSON-подобные документы (BSON). Коллекции по умолчанию не применяют схему, что означает — ваше приложение и тесты должны валидировать структуру данных.

Тестирование валидации схемы

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 }
      }
    }
  }
});

Тест-кейсы:

// Валидный документ — должен пройти
db.users.insertOne({ name: "Alice", email: "alice@test.com", age: 30 });

// Отсутствует обязательное поле — должен не пройти
db.users.insertOne({ name: "Bob" });

// Невалидный тип — должен не пройти
db.users.insertOne({ name: "Charlie", email: "charlie@test.com", age: "thirty" });

Тестирование запросов

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

Тестирование индексов

db.users.createIndex({ email: 1 }, { unique: true });
db.users.find({ email: "alice@test.com" }).explain("executionStats");
// Ищите stage "IXSCAN" (не "COLLSCAN")

Тестирование Redis

Redis — хранилище key-value в памяти для кеширования, сессий, rate limiting и real-time функций.

Тестирование типов данных

# 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 "Новый заказ" "Платёж получен"
LRANGE notifications:123 0 -1

# Set
SADD user:123:roles "admin" "editor" "admin"
SMEMBERS user:123:roles  # {"admin", "editor"} — без дубликатов

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

Тестирование TTL

SET session:abc123 "user-data" EX 60
TTL session:abc123  # Возвращает оставшиеся секунды
EXISTS session:abc123  # 1 (существует)
# Через 60 секунд...
EXISTS session:abc123  # 0 (истёк)

Тестирование инвалидации кеша

  1. Cache hit: Данные в Redis, приложение возвращает закешированное значение.
  2. Cache miss: Данных нет в Redis, приложение запрашивает БД и кеширует результат.
  3. Cache invalidation: Данные обновлены в БД, закешированное значение инвалидировано.
  4. Stale cache: После инвалидации следующий запрос возвращает свежие данные.

Тестирование DynamoDB

DynamoDB — полностью управляемое wide-column хранилище AWS.

Тестирование дизайна ключей

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

Упражнение: Лаборатория тестирования NoSQL

Часть 1: Тестирование MongoDB

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

Задание 1.1: Создайте коллекцию с валидацией схемы для “products”. Проверьте отклонение невалидных документов.

Задание 1.2: Вставьте 1,000 товаров с различными категориями. Напишите aggregation-запросы и проверьте результаты.

Задание 1.3: Создайте составной индекс {category: 1, price: -1}. Проверьте через explain(), что запросы используют индекс.

Часть 2: Тестирование Redis

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

Задание 2.1: Реализуйте и протестируйте хранилище сессий с TTL 300 секунд.

Задание 2.2: Реализуйте и протестируйте rate limiter: 10 запросов в минуту на пользователя.

Задание 2.3: Протестируйте инвалидацию кеша: закешируйте профиль, обновите «БД», инвалидируйте кеш, проверьте, что следующее чтение получит свежие данные.

Часть 3: Тестирование DynamoDB

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

Задание 3.1: Создайте таблицу Orders с userId (partition key) и orderId (sort key). Вставьте 50 заказов и протестируйте паттерны запросов.

Задание 3.2: Протестируйте conditional writes — обновите статус только если он “pending”.

Результаты

  1. MongoDB: Тесты валидации, проверка aggregation, доказательство использования индексов.
  2. Redis: Тесты TTL, rate limiter, инвалидация кеша.
  3. DynamoDB: Тесты паттернов запросов, conditional writes.
  4. Сравнительная таблица различий тестирования SQL и NoSQL.