Тестирование API Node.js с Mocha, Chai и Chai-HTTP
TL;DR
Mocha + Chai + Chai-HTTP позволяют автоматизировать тестирование HTTP API на Node.js: создавать запросы, проверять ответы и ловить регрессии. Настройте отдельную тестовую БД или используйте in-memory MongoDB, изолируйте тесты, добавьте сценарии успеха и ошибок, интегрируйте прогон в CI — и вы получите надёжный набор автотестов для API.

Современная разработка интенсивно использует API. Они связывают клиентские приложения с серверной частью и интегрируют внутренние/внешние сервисы. Надёжность, функциональность и производительность API напрямую влияют на опыт пользователей и целостность системы. Тестирование API на этапе разработки помогает обнаружить ошибки до релиза и снизить риск сбоев в продакшне.
В этой статье описано, как настроить простое Express-приложение с MongoDB и покрыть его автотестами с помощью Mocha, Chai и Chai-HTTP. Приведены пример контроллеров, маршрутов, тестов, рекомендации по изоляции и устранению типичных проблем, а также советы по CI и безопасности.
Основные понятия
- Mocha — тестовый раннер для JavaScript с гибкой организацией тестов и поддержкой асинхронных сценариев. Простая строка: выполняет тесты и даёт отчет.
- Chai — библиотека утверждений (assertions) с понятными интерфейсами expect/should/assert.
- Chai-HTTP — расширение Chai для формирования HTTP-запросов и проверок их ответов.
Что вы получите из этой инструкции
- Настройка Express + MongoDB проекта.
- Примеры контроллеров, маршрутов и server.js.
- Полные примеры тестов POST и GET с Mocha/Chai/Chai-HTTP.
- Лучшие практики: изоляция тестов, in-memory БД, очистка данных, таймауты.
- Рекомендации по CI, отладке проблем и безопасности тестовой среды.
Настройка проекта Express и MongoDB
Создайте Express-сервер и установите зависимости:
npm install express cors dotenv mongoose mongodbСоздайте экземпляр MongoDB локально или кластер в облаке. Скопируйте строку подключения и поместите её в файл .env в корне проекта:
CONNECTION_STRING="connection string"Настройте подключение к базе и определите модель данных пользователя. В примере проект использует эти файлы:
- utils/db.js — конфигурация подключения к MongoDB.
- models/user.model.js — схема пользователя.
В репозитории данного проекта на GitHub можно посмотреть полный код и структуру.
Пример контроллеров: controllers/userControllers.js
Контроллеры управляют добавлением и получением пользователей. Тесты будут проверять, что POST и GET работают корректно.
const User = require('../models/user.model');
exports.registerUser = async (req, res) => {
const { username, password } = req.body;
try {
await User.create({ username, password });
res.status(201).send({ message: 'User registered successfully' });
} catch (error) {
console.log(error);
res.status(500).send({ message: 'An error occurred!! ' });
}
};
exports.getUsers = async (req, res) => {
try {
const users = await User.find({});
res.json(users);
} catch (error) {
console.log(error);
res.status(500).send({ message: 'An error occurred!!' });
}
};Маршрутизация: routes/userRoutes.js
const express = require('express');
const router = express.Router();
const userControllers = require('../controllers/userControllers');
router.post('/api/register', userControllers.registerUser);
router.get('/api/users', userControllers.getUsers);
module.exports = router;Точка входа: server.js
const express = require('express');
const cors = require('cors');
const app = express();
const port = 5000;
require('dotenv').config();
const connectDB = require('./utils/db');
connectDB();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
const userRoutes = require('./routes/userRoutes');
app.use('/', userRoutes);
app.listen(port, () => {
console.log(`Server is listening at http://localhost:${port}`);
});
module.exports = app;Написание и выполнение тестов с Mocha
Установите пакеты для тестирования как dev-зависимости:
npm install mocha chai chai-http --save-devДобавьте в package.json скрипт для запуска тестов:
"scripts": {
"test": "mocha --timeout 10000"
}Параметр –timeout контролирует максимальное время выполнения отдельного теста. 10000 мс (10 с) подходит для тестов, которые делают реальные запросы к базе, но при использовании in-memory БД часто можно уменьшить таймаут.
Тесты POST и GET
Создайте папку test и файл test/user.tests.js с тестами для POST /api/register и GET /api/users.
const chai = require('chai');
const chaiHttp = require('chai-http');
const app = require('../server');
chai.use(chaiHttp);
const expect = chai.expect;
describe('User API', () => {
describe('POST /api/register', () => {
it('should handle user registration', (done) => {
chai.request(app)
.post('/api/register')
.send({ username: 'testUser', password: 'testpassword' })
.end((err, res) => {
if (err) {
expect(res).to.have.status(500);
expect(res.body).to.have.property('message').that.is.equal('An error occurred!!');
} else {
expect(res).to.have.status(201);
expect(res.body).to.have.property('message').equal('User registered successfully');
}
done();
});
});
});
describe('GET /api/users', () => {
it('should fetch all user data', (done) => {
chai.request(app)
.get('/api/users')
.end((err, res) => {
if (err) {
expect(res).to.have.status(500);
expect(res.body).to.have.property('message').that.is.equal('An error occurred while fetching user data');
} else {
expect(res).to.have.status(200);
expect(res.body).to.be.an('array');
}
done();
});
});
});
});Запустите тесты:
npm testЕсли тесты проходят, вы увидите отчёт Mocha. Если какие-то тесты падают, Mocha выводит трассировку и сообщения об ошибках, что помогает быстро локализовать проблему.
Частые причины падения тестов и отладка
- Неправильная строка подключения к БД или отсутствие миграций. Проверьте .env и utils/db.js.
- Неточности в схеме модели (обязательные поля, валидация) — добавьте проверки перед create.
- Тесты не изолированы: предыдущие тесты оставляют данные, что меняет результат последующих. Создавайте и очищайте тестовую БД между тестами.
- Таймауты: медленные операции требуют увеличения –timeout или оптимизации запросов.
- Конфликты портов: если сервер уже запущен на порту, тесты не смогут поднять приложение. В тестах можно экспортировать app без app.listen и запускать отдельный сервер или использовать supertest/chai-http, обращаясь к экспортированному app.
Лучшие практики и рекомендации
1) Изоляция тестовой среды
Используйте отдельную тестовую базу данных или in-memory MongoDB (mongodb-memory-server) для быстрого и чистого прогонки тестов. Это упрощает очистку и ускоряет прогоны.
Короткое объяснение: mongodb-memory-server запускает MongoDB в памяти, поэтому тесты становятся детерминированными и быстрыми.
Пример установки:
npm install --save-dev mongodb-memory-serverИ в тестах вы можете поднять in-memory сервер в before() и остановить в after().
2) Очистка данных между тестами
В beforeEach/afterEach удаляйте коллекции или используйте транзакции (если поддерживается). Это предотвращает перенос состояния между тестами.
3) Моки и стабы
Для внешних сервисов (почта, очереди, сторонние API) используйте моки. Для MongoDB можно комбинировать in-memory сервер и sinon для заглушек.
4) Тестовые данные и фабрики
Создавайте фабрики тестовых данных или используйте fixtures. Это делает тесты читаемыми и предсказуемыми.
5) Таймауты и асинхронность
Всегда учитывайте асинхронность. Mocha поддерживает done(), возвращение Promise или async/await. Пример на async/await:
it('async test example', async () => {
const res = await chai.request(app).get('/api/users');
expect(res).to.have.status(200);
});6) Тесты ошибок и крайних случаев
Покрывайте не только успешные сценарии: неверные данные, дублирование пользователя, проблемы подключения к БД, некорректные права доступа.
Примеры дополнительных тестов и критерии приёмки
Критерии приёмки для регистрации пользователя:
- При валидных username и password API возвращает 201 и сообщение об успехе.
- При повторной регистрации с тем же username возвращается 409 или 400 с объяснением.
- При отсутствии обязательного поля возвращается 400 с описанием ошибки.
- После успешной регистрации пользователь присутствует в коллекции users.
Пример теста для проверки дубликата:
it('should not allow duplicate username', async () => {
await chai.request(app).post('/api/register').send({ username: 'dupe', password: 'p' });
const res = await chai.request(app).post('/api/register').send({ username: 'dupe', password: 'p' });
expect(res).to.have.status(409);
});Примечание: В коде контроллера нужно добавить проверку существующего пользователя и возвращать 409 Conflict.
Интеграция тестов в CI
- Добавьте шаг npm test в pipeline (GitHub Actions, GitLab CI, CircleCI).
- В CI поднимайте либо реальную тестовую БД, либо используйте mongodb-memory-server.
- Убедитесь, что переменные окружения для CI настроены отдельно и безопасно (секреты в переменных CI).
Пример workflow (GitHub Actions, упрощённо):
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: 16
- run: npm ci
- run: npm testРешение спорных случаев: когда тестирование может не помочь
- Если логика зависит от внешнего API с нестабильным поведением, unit-тесты с моками помогут, но интеграционные тесты всё равно будут флаговать флаки. Необходим гибрид моков и выделенных интеграционных прогонов с реальными сервисами.
- Автотесты не заменяют ручное тестирование UX и нагрузочного тестирования — они дополняют их.
Безопасность тестовой среды
- Никогда не используйте production-CONNECTION_STRING в тестах.
- Ограничьте права тестовой БД: тестовая учётная запись не должна иметь возможности удалять продакшн-данные.
- Чувствительные секреты храните в CI secrets, не в репозитории.
Рекомендации по хранению тестов и структуре проекта
- test/ — все тесты проекта.
- fixtures/ или factories/ — данные для тестов.
- scripts/ci-setup.js — скрипты для подготовки тестовой среды в CI.
- utils/testHelpers.js — общие функции для очистки DB, создания токенов и пр.
Чек-листы для ролей
Разработчик:
- Написал unit и интеграционные тесты для новых эндпоинтов.
- Добавил обработку ошибок и корректные HTTP-статусы.
- Обновил документацию API.
Тестер:
- Прогнал тесты локально и в CI.
- Проверил сценарии ошибок и граничные случаи.
- Подтвердил, что тесты изолированы и детерминированы.
Оператор/DevOps:
- Настроил CI для запуска тестов на PR.
- Обеспечил безопасные переменные окружения для тестовой среды.
- Настроил мониторинг времени выполнения тестов для выявления регрессий.
Decision tree: выбрать in-memory DB или реальную тестовую БД
flowchart TD
A[Начать тестирование] --> B{Требуется тестировать интеграцию с реальной MongoDB?}
B -- Да --> C[Поднять тестовую БД 'отдельный экземпляр']
B -- Нет --> D[Использовать mongodb-memory-server]
C --> E{CI среда доступна?}
E -- Да --> F[Запускать тесты в CI с тестовой БД]
E -- Нет --> G[Документация: как поднять локально тестовую БД]
D --> H[Изолированные, быстрые тесты]
F --> I[Проход CI]
G --> I
H --> IПримеры приёма и тестовых сценариев (минимальный набор)
- Регистрация: валидные данные => 201
- Регистрация: дубликат username => 409
- Регистрация: отсутствует password => 400
- Получение списка: авторизация отсутствует => 401 (если требуется)
- Получение списка: успешный запрос => 200 + массив
Шаблон для тестовой стратегии (мини-процедура)
- Подготовить тестовую среду (in-memory или выделенная БД).
- Очистить коллекции перед каждым тестом.
- Загружать простые фикстуры в beforeEach при необходимости.
- Выполнить тестовые запросы (успех/ошибки/производительность).
- Убедиться в корректности статусов и структуры ответов.
- Очищать данные и выключать соединения в after/afterEach.
Заключение
Mocha в связке с Chai и Chai-HTTP — простой и мощный набор инструментов для тестирования API на Node.js. Автоматизированные тесты помогают обнаруживать регрессии, повышают надёжность релизов и упрощают поддержку кода.
Важно: комбинируйте unit и интеграционные тесты, используйте in-memory БД или изолированную тестовую БД, добавляйте проверки ошибок и интеграцию в CI. Это позволит своевременно ловить проблемы и выпускать более качественное ПО.
Краткое содержание
- Настройте проект: Express, MongoDB, модели и контроллеры.
- Пишите тесты с Mocha/Chai/Chai-HTTP для всех сценариев.
- Изолируйте тестовую среду и интегрируйте прогоны в CI.
Дополнительные ресурсы
- Репозиторий проекта на GitHub — содержит полный пример кода и конфигурации.
Важно: тесты должны выполняться в отдельной среде и не иметь доступа к продакшн-данным.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента