Тестирование в Node.js

В данной статье будут разобраны вещи и инструменты, которые необходимы для тестирования сервера на Node.js. Будут кратко рассмотрены такие фреймворки как Mocha и Chai, которые упростят тестирование в разы. Будет написан тест для "реального" сервера.
Инструменты:
1. Mocha - Окружение для тестов

Mocha - это JavaScript фреймворк, который позволяет выполнять тесты асинхронно. Другими словами, это среда для выполнения тестов.

Главные возможности Mocha:

  • простая поддержка асинхронности, включая промисы;
  • поддержка тайм-аутов;
  • before, after, beforeEach, afterEach - интерфейс, который позволит выполнять код до или после каждого теста (например, очистить базу данных перед тестированием запросов на сервер);
  • позволяет использовать любую библиотеку утверждений. В данной статье используется Chai.

2. Chai - Библиотека утверждений

Библиотека утверждений используется для установки условий. Если одно из этих условий не выполняется, то тест проваливается.

Главные возможности Chai:

should, expect, assert - это основной интерфейс библиотеки Chai. Значение этих ключевых слов то же самое, как и в английском языке. Например, serverResponse.should.have.status
(200)
или expect(res.body).have.property
('message')
- это рабочий код, если вы используете Chai.


Философия Теста
Почему это называется модульным (Unit) тестированием? Потому что его цель - тестировать отдельную часть приложения: endpoint сервера, сервис, метод.

Лучший подход к модульному тестированию состоит из трех частей:

  1. Подготовка - определение всех начальных условий и входных данных.
  2. Действие - действие над юнитом (функцией, методом, объектом), который нужно протестировать.
  3. Утверждение - убедиться, что условия тестирования выполнены и соблюдены.

Использование:
Как указано выше, Mocha предоставляет среду для выполнения тестов. Mocha - крайне незамысловатый в обращении фреймворк. В большинстве случаев можно обойтись двумя ключевыми словами:

  1. describe - для создания среды, в которой будет происходить тестирование
  2. it - для установки условий и определения тех случаев теста, которые нужно пройти

Главное в Chai - это использование простого "человеческого языка" для повышения читабельности тестов. to, be, equal, have, not… - интерфейс для установки утверждений, который предоставляется Chai.

Вот простой пример теста:


Продвинутое использование:
Если вы хотите больше знать о "реальном" тестировании, тогда посмотрите на код ниже. Данный пример иллюстрирует тестирование простого серверного API.

Положим, что у нас есть сервер с двумя конечными точками, на которые мы можем делать GET запросы, /sum и /square:
Теперь давайте протестируем этот сервер:
Что здесь происходит:

  1. Подготовка: определение входных данных и ожидаемых результатов.

  2. Действие: проходим по массиву sums. Делаем GET запрос для каждой суммы с х и у параметрами.

  3. Утверждение: определим ожидаемый статус ответов с сервера и значения.

  4. Трюк: заставить it блок дождаться всех ответов с сервера. Так как в it блоке мы отправляем череду запросов на сервер, то следует дождаться последнего ответа с сервера и только тогда вызвать done. Таким образом, мы будем уверены в том, что все ответы с сервера проверены и обработаны.

Сможете написать тест для конечной точки /square сами?

Это все. Тестирование не составит особого труда, если вы точно знаете что тестировать и используете распространенные сценарии теста, например Arrange-Act-Aside. Что действительно рекомендую, так это углубиться в документацию Mocha и Chai, чтобы изучить продвинутые темы тестирования инструментов.


Полезные заметки
Читаемость важна
Для этого стоит использовать BDD-style подтверждения, которые предоставляют интерфейс с "читабельными" ключевыми словами. should, expect, assert в Chai идеально подходят для этой проблемы.

Знайте то, что вы будете тестировать
Правильное тестирование внутренних вещей, таких как бэкенд сервера, обходится очень дорого с точки зрения времени и не гарантирует того, что внешние вещи будут работать безошибочно.

В то же время правильное тестирование внешних вещей, таких как API сервера, обходится не так дорого; протестирует внутренние вещи косвенно, а внешние - явно.

Не используйте "фальшивые" данные, приближайте релизные условия
Хороший генератор "реальных" данных: Faker.

Максимально упрощайте ваши инструменты, уменьшайте использование сторонних сервисов и абстракций, когда пишете тест.

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

before и beforeEach не равны
Код внутри before блока выполнится один раз перед всеми тестами "родительского" describe блока Код внутри beforeEach блока будет выполнен перед каждым тестом "родительского" describe блока.

Тоже самое для after и afterEach.

Используем done для синхронных проверок


Без вызова done, блок it будет просто отправлять someAsyncWork и завершаться до того, как callback из someAsync work вызовется. В коде сверху it будет завершаться, кода done будет вызван. Таким образом, без вызова done мы получим "132", а с вызовом - "123".

Тесты должны быть независимы друг от друга

Это предпочитаемый подход, когда первый тест не зависит и не влияет на второй тест и наоборот.
Спасибо за внимание!