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

Тестирование API Node.js с Mocha, Chai и Chai-HTTP

7 min read Разработка Обновлено 15 Dec 2025
Тестирование API Node.js: Mocha, Chai и Chai-HTTP
Тестирование 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

Отчёт об успешных тестах API в терминале

Если тесты проходят, вы увидите отчёт 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 + массив

Шаблон для тестовой стратегии (мини-процедура)

  1. Подготовить тестовую среду (in-memory или выделенная БД).
  2. Очистить коллекции перед каждым тестом.
  3. Загружать простые фикстуры в beforeEach при необходимости.
  4. Выполнить тестовые запросы (успех/ошибки/производительность).
  5. Убедиться в корректности статусов и структуры ответов.
  6. Очищать данные и выключать соединения в after/afterEach.

Заключение

Mocha в связке с Chai и Chai-HTTP — простой и мощный набор инструментов для тестирования API на Node.js. Автоматизированные тесты помогают обнаруживать регрессии, повышают надёжность релизов и упрощают поддержку кода.

Важно: комбинируйте unit и интеграционные тесты, используйте in-memory БД или изолированную тестовую БД, добавляйте проверки ошибок и интеграцию в CI. Это позволит своевременно ловить проблемы и выпускать более качественное ПО.

Краткое содержание

  • Настройте проект: Express, MongoDB, модели и контроллеры.
  • Пишите тесты с Mocha/Chai/Chai-HTTP для всех сценариев.
  • Изолируйте тестовую среду и интегрируйте прогоны в CI.

Дополнительные ресурсы

  • Репозиторий проекта на GitHub — содержит полный пример кода и конфигурации.

Важно: тесты должны выполняться в отдельной среде и не иметь доступа к продакшн-данным.

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

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

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро