Гид по технологиям

Тестирование Mongoose моделей с mongodb-memory-server и Jest

8 min read Разработка Обновлено 19 Dec 2025
Тестирование Mongoose с mongodb-memory-server
Тестирование Mongoose с mongodb-memory-server

Прозрачные мерные чашки на деревянной поверхности

Зачем тестировать модели в памяти

При интеграционном тестировании Mongoose моделей важно не трогать реальную базу данных проекта: фейковые записи могут загрязнить рабочие данные, тесты в облаке становятся медленными или дорогими, а настройка локальной БД на CI усложняет конвейер. mongodb-memory-server запускает реальный экземпляр MongoDB в памяти: база ведёт себя как «настоящая», но данные не пишутся на диск и исчезают после остановки сервера. Это делает тесты быстрыми, детерминированными и безопасными для реальной БД.

Важно: mongodb-memory-server не заменяет все виды тестов — он отлично подходит для unit/integration тестов моделей и логики доступа к данным, но не для проверки сетевой конфигурации, production-оптимизаций или распределённого поведения.

Что понадобится перед началом

  • Node.js (LTS) и npm/yarn
  • Базовые знания Mongoose и Jest
  • Проектная папка для экспериментов

Совет: запускать тесты локально и в CI с ключом –runInBand (как в примере) удобно для упрощённой отладки подключения к MongoMemoryServer.

План результата

Мы реализуем:

  • Mongoose модель Todo (поля item и completed).
  • Три набора тестов: успешное сохранение, отсутствие требуемого поля, неправильный тип поля.
  • Файлы: package.json, todo.model.js, setupdb.js, todo.model.test.js

Ниже пошаговая инструкция с кодом, пояснениями и набором практических приёмов.

Создание проекта и установка зависимостей

Откройте терминал, создайте папку и перейдите в неё:

        `mkdir mongoose-model-test  
cd mongoose-model-test  
`
    

Инициализируйте npm:

        `npm init -y  
`
    

Установите mongoose:

        `npm install mongoose  
`
    

Установите mongodb-memory-server:

        `npm install mongodb-memory-server  
`
    

Установите jest для тестов:

        `npm install jest  
`
    

В package.json добавьте/замените блок scripts и настройку окружения для jest:

        `"scripts": {  
    "test": "jest --runInBand --detectOpenHandles"  
},  
"jest": {  
    "testEnvironment": "node"  
},  
`
    

Модель Mongoose (todo.model.js)

Создайте файл todo.model.js со схемой для задач (todo). Схема ожидает поле item (String) и completed (Boolean) — оба поля обязательны.

        `const mongoose = require("mongoose")  
const { Schema } = mongoose  
  
const TodoSchema = new Schema({  
    item: {  
        type: String,  
        required: true  
    },  
    completed: {  
        type: Boolean,  
        required: true  
    }  
})  
`
    

Экспорт модели в том же файле:

        `module.exports = mongoose.model("Todo", TodoSchema)  
`
    

Пояснение: модель используется как фабрика документов и даёт API (.save(), .find(), .findById() и т. д.). Объявление required помогает ловить ошибки валидации ещё на уровне модели.

Настройка in-memory базы (setupdb.js)

Создайте файл setupdb.js. В нём — код для поднятия MongoMemoryServer, подключения Mongoose и очистки между тестами.

        `const mongoose = require("mongoose");  
const { MongoMemoryServer } = require("mongodb-memory-server");  
`
    

Функция подключения (connectDB):

        `let mongo = null;  
  
const connectDB = async () => {  
  mongo = await MongoMemoryServer.create();  
  const uri = mongo.getUri();  
  
  await mongoose.connect(uri, {  
    useNewUrlParser: true,  
    useUnifiedTopology: true,  
  });  
};  
`
    

Функция остановки и удаления базы (dropDB):

        `const dropDB = async () => {  
  if (mongo) {  
    await mongoose.connection.dropDatabase();  
    await mongoose.connection.close();  
    await mongo.stop();  
  }  
};  
`
    

Функция очистки коллекций после каждого теста (dropCollections):

        `const dropCollections = async () => {  
  if (mongo) {  
    const collections = await mongoose.connection.db.collections();  
    for (let collection of collections) {  
      await collection.deleteMany({});  
    }  
  }  
};  
`
    

Экспорт:

        `module.exports = { connectDB, dropDB, dropCollections}  
`
    

Важно: мы используем deleteMany({}) вместо устаревшего collection.remove() — это современная и безопасная операция очистки.

Написание тестов (todo.model.test.js)

Создайте файл todo.model.test.js. В нём подключаем Mongoose, модель и функции из setupdb.js:

        `const mongoose = require("mongoose");  
const { connectDB, dropDB, dropCollections } = require("./setupdb");  
const Todo = require("./todo.model");  
`
    

Подключение/очистка тестовой БД через Jest хуки beforeAll/afterEach/afterAll:

        `beforeAll(async () => {  
  await connectDB();  
});  
  
afterAll(async () => {  
  await dropDB();  
});  
  
afterEach(async () => {  
  await dropCollections();  
});  
`
    

Тестовый блок и тесты — позитивный и два негативных:

        `describe("Todo Model", () => {  
  it("should create a todo item successfully", async () => {  
    let validTodo = {  
      item: "Do the dishes",  
      completed: false,  
    };  
    const newTodo = new Todo(validTodo);  
    await newTodo.save();  
    expect(newTodo._id).toBeDefined();  
    expect(newTodo.item).toBe(validTodo.item);  
    expect(newTodo.completed).toBe(validTodo.completed);  
  });  
  
  it("should fail for todo item without required fields", async () => {  
    let invalidTodo = {  
      item: "Do the dishes",  
    };  
    try {  
      const newTodo = new Todo(invalidTodo);  
      await newTodo.save();  
    } catch (error) {  
      expect(error).toBeInstanceOf(mongoose.Error.ValidationError);  
      expect(error.errors.completed).toBeDefined();  
    }  
  });  
  
  it("should fail for todo item with fields of wrong type", async () => {  
    let invalidTodo = {  
      item: "Do the dishes",  
      completed: "False"  
    };  
    try {  
      const newTodo = new Todo(invalidTodo);  
      await newTodo.save();  
    } catch (error) {  
      expect(error).toBeInstanceOf(mongoose.Error.ValidationError);  
      expect(error.errors.completed).toBeDefined();  
    }  
  });  
});  
`
    

Пояснение: в негативных тестах мы ожидаем mongoose.Error.ValidationError — это стандартная ошибка валидации модели Mongoose.

Запуск тестов

Выполните команду:

npm test

Jest запустит тесты, подняв MongoMemoryServer, подключившись и очистив данные между тестовыми случаями.

Отладка и типичные проблемы

  • Тесты висят/не завершатся: попробуйте добавить –runInBand (в примере уже есть) или убедитесь, что в afterAll вы корректно вызываете mongoose.connection.close() и mongo.stop().
  • Ошибки подключения: убедитесь, что версия mongodb-memory-server совместима с вашей версией Node.js и mongoose.
  • Миграции/индексы: mongodb-memory-server поднимает чистую БД — индексы автоматически создаются при первом обращении к модели, но если вы рассчитываете на внешние миграции, настройте их в beforeAll.

Important: не используйте in-memory БД для проверки долгоживущих оптимизаций индексирования или поведения при отказах кластера — это другие уровни тестирования.

Когда подход не подходит (примеры)

  • Тестирование распределённого поведения (репликация, шардирование) — mongodb-memory-server эмулирует одиночный экземпляр.
  • Тесты, зависящие от файловой системы MongoDB или внешних инструментов мониторинга.
  • Проверка производительности под нагрузкой — in-memory БД часто быстрее и не отражает real-world I/O.

Альтернативные подходы

  • Локальный контейнер MongoDB (Docker) — даёт более похожую на прод среду, но медленнее и требует управления контейнерами.
  • Тестовая облачная БД — подходит при необходимости близости к прод, но дороже и сложнее в автоматизации.
  • Подмены/моки для Mongoose моделей — быстры, но вы не проверяете реальную валидацию и поведение драйвера.

Практическая мини-методика для команды

  1. Подключите mongodb-memory-server в рамках тестовой среды (setupdb.js).
  2. Пишите тесты, которые проверяют валидацию схемы, сохранение и чтение.
  3. Очистку коллекций выполняйте после каждого теста (deleteMany) — это гарантирует изоляцию.
  4. Выключайте сервер и закрывайте соединения в afterAll.
  5. На CI используйте параметр –runInBand при необходимости последовательного выполнения.

Роли и чек-листы

Разработчик:

  • Добавить тесты для позитивных и негативных сценариев.
  • Проверить, что коллекции очищаются между тестами.
  • Не оставлять реальные строки подключения в тестах.

Ревьюер:

  • Убедиться, что ошибки валидации явно проверяются (toBeInstanceOf).
  • Проверить корректность типов в тестовых данных.

Инженер CI:

  • Настроить кеш npm для ускорения сборок.
  • Убедиться, что CI-образ содержит совместимую версию Node.js.

Критерии приёмки

  • Все тесты в jest проходят локально и в CI.
  • Нет потерянных подключений (нет висящих процессов afterAll).
  • Коллекции очищаются между тестами.

Тестовые случаи и критерии приёмки

  1. Успешное сохранение
    • Вход: объект с item: String, completed: Boolean
    • Ожидается: newTodo._id определён, поля совпадают
  2. Отсутствует обязательное поле
    • Вход: объект без completed
    • Ожидается: ValidationError с error.errors.completed
  3. Неверный тип поля
    • Вход: completed: “False”
    • Ожидается: ValidationError

Советы по безопасности и приватности

  • В тестах не храните реальные персональные данные. Если требуется тестировать на похожих данных, используйте обезличенные или синтетические наборы.
  • Проверьте, что конфигурация CI не публикует логи с чувствительной информацией о подключении.

Совместимость и миграции

  • mongodb-memory-server активно развивается и может иметь breaking changes между мажорными версиями. Перед обновлением проверьте changelog и тесты.
  • Mongoose также меняет настройки подключения: опции useNewUrlParser и useUnifiedTopology были рекомендованы для «старых» версий. В новых версиях они могут быть не обязательны — смотрите документацию вашей версии.

Набор типичных ошибок и их решения

  • Ошибка: ReferenceError: MongoMemoryServer is not defined Решение: Убедитесь, что импорт { MongoMemoryServer } написан корректно и что пакет установлен.

  • Ошибка: EADDRINUSE при старте MongoMemoryServer Решение: Проверьте, не запущен ли другой Mongo на том же порту; mongodb-memory-server обычно выбирает свободный порт, но в редких условиях конфликт возможен.

Небольшой чек-лист для добавления новых тестов моделей

  • Есть позитивный сценарий сохранения
  • Есть негативные сценарии для required и типов
  • Очистка коллекций после каждого теста
  • Закрытие соединений в afterAll
  • Тесты детерминированы и не зависят от внешних сервисов

Короткий глоссарий (1 строка)

  • Mongoose — ODM для MongoDB в Node.js.
  • mongodb-memory-server — npm-пакет, запускающий MongoDB в памяти.
  • Jest — тестовый раннер для JavaScript/Node.js.

Краткое объявление для команды (100–200 слов)

В проект добавлен шаблон для тестирования Mongoose моделей с помощью mongodb-memory-server и Jest. Это позволит нам запускать быстрые, изолированные тесты моделей без риска повредить рабочую базу. В репозитории появился пример с моделью todo, настройкой setupdb.js и тестами todo.model.test.js. Инструкция включает сценарии успешного сохранения, проверки отсутствующих обязательных полей и проверки типов. Пожалуйста, используйте этот шаблон при добавлении тестов для новых моделей и убедитесь, что они выполняются в CI.

Соц-превью

OG title: Тестирование Mongoose с mongodb-memory-server
OG описание: Быстрое и безопасное тестирование Mongoose моделей в памяти с примерами на Jest.

Итоги

  • mongodb-memory-server делает тесты моделей быстрыми и безопасными, поднимая реальную MongoDB в памяти.
  • В примере показано создание модели, настройка in-memory БД и три ключевых теста.
  • Используйте предложенные хуки и чек-листы, чтобы тесты были детерминированными и чистыми.

Спасибо — если нужно, могу подготовить готовый репозиторий с этими файлами или добавить дополнительные тесты (например, для индексов, виртуальных полей или middleware).

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Будильники и таймеры на HomePod — как настроить
Умный дом

Будильники и таймеры на HomePod — как настроить

Disk Utility на Mac: проверка, ремонт и форматирование
Mac

Disk Utility на Mac: проверка, ремонт и форматирование

Мышь для Mac: подключение, настройка и отладка
Аксессуары Mac

Мышь для Mac: подключение, настройка и отладка

Пакетная обрезка и изменение размера в Lightroom
Фотография

Пакетная обрезка и изменение размера в Lightroom

Команда head в Linux — руководство и примеры
Linux

Команда head в Linux — руководство и примеры

Планшет на Raspberry Pi: как собрать
Raspberry Pi

Планшет на Raspberry Pi: как собрать