Как тестировать модели Mongoose с помощью сервера памяти Mongo

9
технологии 6.webp

Последнее обновление 06.01.2023 — Василий Иванов

Тестирование моделей Mongoose может быть сложной задачей, потому что вам нужно написать тесты, которые не мешают вашей реальной базе данных. Пакет сервера памяти MongoDB предлагает простое решение. Он позволяет хранить данные испытаний в памяти приложения.

В этом руководстве вы создадите простую модель Mongoose и напишете тесты, используя Jest и сервер памяти MongoDB.

Что такое сервер памяти MongoDB?

Последнее, что вам нужно, — это сохранить поддельные данные в вашей реальной базе данных, что может произойти, если вы подключитесь к ней во время тестирования. Вместо этого вы можете использовать отдельный локальный экземпляр MongoDB для хранения ваших данных. Хотя это работает, это невозможно, если ваши тесты выполняются в облаке. Кроме того, подключение и запросы к реальной базе данных во время каждого теста могут быть дорогостоящими.

По теме:  Как опубликовать пакет в npm

Однако сервер памяти MongoDB запускает настоящий сервер MongoDB и позволяет хранить тестовые данные в памяти. Это делает его быстрее, чем использование локальной базы данных MongoDB, поскольку данные не записываются на физический диск.

Создание модели мангуста

Модели Mongoose предоставляют интерфейс для взаимодействия с базой данных MongoDB. Чтобы создать их, вам нужно скомпилировать их из схемы Mongoose, которая определяет вашу модель данных MongoDB. В этом руководстве будет использоваться схема документа списка дел. Он будет содержать заголовок и заполненные поля.

Выполните следующую команду в терминале, чтобы создать новую папку и перейти к ней.

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

Инициализируйте npm с помощью следующей команды:

npm init -y

Флаг -y указывает npm создать файл package.json со значениями по умолчанию.

Выполните эту команду, чтобы установить пакет mongoose:

npm install mongoose

Создайте новый файл с именем todo.model.js и определите схему todo:

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

В конце этого файла создайте и экспортируйте модель todo:

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

Планирование тестов

При написании тестов вы хотите заранее спланировать, что вы будете тестировать. Это гарантирует, что вы протестируете все функциональные возможности вашей модели.

Из созданной нами модели Mongoose задача должна содержать элемент типа String и заполненное поле типа Boolean. Оба эти поля являются обязательными. Это означает, что, как минимум, наш тест должен обеспечивать:

  • Действительные элементы успешно сохранены в базе данных.
  • Элементы без обязательных полей не сохраняются.
  • Элементы с полями недопустимого типа не сохраняются.

Мы напишем эти тесты в одном тестовом блоке, так как они связаны. В Jest вы определяете этот тестовый блок с помощью функции описания. Например:

describe('Todo Model Test', () => {
// Your tests go here
}

Настройка базы данных

Чтобы настроить сервер памяти MongoDB, вы создадите новый экземпляр сервера памяти Mongo и подключитесь к Mongoose. Вы также создадите функции, которые будут отвечать за удаление всех коллекций в базе данных и отключение от экземпляра сервера памяти Mongo.

Выполните следующую команду, чтобы установить mongodb-memory-server.

npm install mongodb-memory-server

Создайте новый файл с именем setuptestdb.js и импортируйте mongoose и mongodb-memory-server.

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

Затем создайте функцию connectDB(). Эта функция создает новый экземпляр сервера памяти Mongo и подключается к Mongoose. Вы будете запускать его перед всеми тестами для подключения к тестовой базе данных.

let mongo = null;

const connectDB = async () => {
mongo = await MongoMemoryServer.create();
const uri = mongo.getUri();

await mongoose.connect(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
});
};

Создайте функцию dropDB(), добавив следующий код. Эта функция удаляет базу данных, закрывает соединение Mongoose и останавливает экземпляр сервера памяти Mongo. Вы запустите эту функцию после завершения выполнения всех тестов.

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

Последняя функция, которую вы создадите, называется dropCollections(). Из него выпадают все созданные коллекции Mongoose. Вы будете запускать его после каждого теста.

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

Наконец, экспортируйте функции conenctDB(), dropDB() и dropCollections().

module.exports = { connectDB, dropDB, dropCollections}

Написание тестов

Как уже упоминалось, вы будете использовать Jest для написания тестов. Выполните следующую команду, чтобы установить jest.

npm install jest

В файле package.json настройте jest. Замените существующий блок «скрипты» следующим:

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

Создайте новый файл с именем todo.model.test.js и импортируйте библиотеку mongoose, модель todo и функции conenctDB(), dropDB() и dropCollections():

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

Вам нужно запустить функцию connectDB() перед выполнением всех тестов. С Jest вы можете использовать метод beforeAll().

Вам также необходимо запустить функции очистки. После каждого теста запускайте функцию dropCollections() и функцию dropDB() после всех тестов. Вам не нужно делать это вручную, вы можете использовать методы afterEach() и afterAll() из Jest.

Добавьте следующий код в файл todo.model.test.js, чтобы настроить и очистить базу данных.

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 = await Todo(validTodo);
await newTodo.save();
expect(newTodo._id).toBeDefined();
expect(newTodo.item).toBe(validTodo.item);
expect(newTodo.completed).toBe(validTodo.completed);
});
});

Это создает новый документ в базе данных, содержащий данные в переменной validTodo. Затем возвращенный объект проверяется на соответствие ожидаемым значениям. Чтобы этот тест прошел, возвращаемое значение должно иметь идентификатор объекта. Кроме того, значения в элементе и заполненных полях должны совпадать со значениями в объекте validTodo.

Помимо тестирования обычного варианта использования, вам также необходимо протестировать неудачный вариант использования. Из запланированных нами тестов вам нужно протестировать модель мангуста с объектом todo, с отсутствующим обязательным полем и одним с неправильным типом.

Добавьте второй тест в тот же блок описания следующим образом:

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

Модель Todo mongoose ожидает как элемент, так и заполненные поля. Если вы попытаетесь сохранить задачу без одного из этих полей, должно появиться сообщение об ошибке. Этот тест использует блок try…catch для перехвата сгенерированной ошибки. Тест предполагает, что ошибки будут ошибкой проверки мангуста и связаны с отсутствующим заполненным полем.

Чтобы проверить, выдает ли модель ошибку при использовании значений неправильного типа, добавьте следующий код в блок описания.

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

Обратите внимание, что значение заполненного поля является строкой, а не логическим значением. Тест ожидает, что будет выдана ошибка проверки, поскольку модель ожидает логическое значение.

MongoMemoryServer и Jest — отличная команда

Пакет mongo-memory-server npm предоставляет простое решение для тестирования моделей Mongoose. Вы можете хранить фиктивные данные в памяти, не затрагивая базу данных вашего приложения.

Вы можете использовать MongoMemoryServer с Jest для написания тестов для моделей Mongoose. Обратите внимание, что он не охватывает все возможные тесты, которые вы можете написать для своих моделей. Эти тесты будут зависеть от вашей схемы.