Настройка тестового окружения

Для начала работы с Mocha, необходимо установить сам фреймворк и связанные с ним зависимости. Mocha можно установить через пакетный менеджер npm, который используется в Node.js проектах. Для этого в корневой директории проекта выполняется следующая команда:

npm install mocha --save-dev

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

npx mocha --version

Для удобства тестирования рекомендуется установить дополнительные инструменты, такие как Chai — библиотеку для утверждений (assertions), которая интегрируется с Mocha и упрощает создание тестов.

npm install chai --save-dev

После установки всех зависимостей, проект будет готов к запуску тестов с использованием Mocha.

Структура проекта и конфигурация

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

Пример структуры проекта:

/my-project
  /node_modules
  /test
    test-example.js
  package.json
  index.js

Файл test-example.js будет содержать тесты для различных частей приложения.

Конфигурация Mocha

Mocha можно настроить с помощью различных опций. Основные конфигурации можно указать в командной строке при запуске тестов или через файл конфигурации. Например, можно указать директорию с тестами, включить или отключить флаг “watch” для автоматического повторного запуска тестов при изменении файлов, а также выбрать библиотеку утверждений.

Пример команды для запуска тестов с дополнительными опциями:

npx mocha --reporter spec --timeout 5000 --recursive ./test

Здесь:

  • --reporter spec — задает формат вывода результатов тестов.
  • --timeout 5000 — увеличивает таймаут выполнения теста до 5000 миллисекунд.
  • --recursive — включает рекурсивный поиск тестов в подкаталогах.
  • ./test — директория с тестами.

Можно также использовать файл конфигурации Mocha для более удобной настройки. Для этого создается файл .mocharc.json в корне проекта. Пример конфигурации:

{
  "reporter": "spec",
  "timeout": 5000,
  "recursive": true
}

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

Использование тестового фреймворка Chai

Chai — это библиотека для написания утверждений, которая предоставляет различные способы проверки правильности работы кода. Она поддерживает три основных стиля:

  • Assert — традиционный стиль с функциями, возвращающими утверждения.
  • Expect — более удобный и читаемый стиль с использованием цепочек.
  • Should — позволяет использовать утверждения через методы.

Пример использования Chai с Mocha:

const chai = require('chai');
const expect = chai.expect;

describe('Математические операции', function() {
  it('должно возвращать 4 при сложении 2 и 2', function() {
    const result = 2 + 2;
    expect(result).to.equal(4);
  });
});

В этом примере используется стиль expect, который позволяет создавать цепочку утверждений. Тест проверяет, что результат сложения 2 и 2 будет равен 4.

Автоматический запуск тестов при изменениях

Для удобства можно настроить автоматический запуск тестов при изменении файлов с помощью пакета nodemon или аналогичных инструментов. Для этого можно установить nodemon как зависимость для разработки:

npm install nodemon --save-dev

В файле package.json добавляется скрипт, который будет отслеживать изменения в тестовых файлах и запускать Mocha:

{
  "scripts": {
    "test": "mocha",
    "dev": "nodemon --exec 'npm test' --ext js,json"
  }
}

После этого можно запускать тесты с помощью команды:

npm run dev

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

Интеграция с CI/CD

Mocha легко интегрируется с различными системами непрерывной интеграции (CI), такими как Jenkins, CircleCI, Travis CI и другими. Для этого достаточно добавить запуск тестов Mocha в процесс сборки.

Пример конфигурации для Travis CI:

language: node_js
node_js:
  - "14"
install:
  - npm install
script:
  - npm test

Этот конфигурационный файл для Travis CI автоматически выполнит тесты при каждом коммите в репозиторий.

Работа с асинхронными тестами

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

  1. Передача callback-функции в тест — Mocha ожидает вызова функции done(), чтобы завершить тест.
it('должен вернуть результат через 1 секунду', function(done) {
  setTimeout(function() {
    expect(true).to.be.true;
    done();
  }, 1000);
});
  1. Возвращение промиса — Mocha будет ожидать завершения промиса.
it('должен вернуть результат через 1 секунду', function() {
  return new Promise(resolve => {
    setTimeout(function() {
      expect(true).to.be.true;
      resolve();
    }, 1000);
  });
});
  1. Использование async/await — асинхронный код можно писать более понятно, используя async/await.
it('должен вернуть результат через 1 секунду', async function() {
  await new Promise(resolve => setTimeout(resolve, 1000));
  expect(true).to.be.true;
});

Каждый из этих методов имеет свои особенности и предпочтения в зависимости от конкретных требований теста.

Создание тестов для модулей

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

Пример тестирования модуля:

const math = require('../math'); // импортируем модуль для тестирования
const chai = require('chai');
const expect = chai.expect;

describe('Математические операции', function() {
  describe('Сложение', function() {
    it('должно вернуть правильный результат', function() {
      const result = math.add(2, 3);
      expect(result).to.equal(5);
    });
  });

  describe('Вычитание', function() {
    it('должно вернуть правильный результат', function() {
      const result = math.subtract(5, 3);
      expect(result).to.equal(2);
    });
  });
});

В этом примере тестируются функции add и subtract из модуля math. Для каждого метода создается отдельный блок describe, который группирует связанные тесты. Это помогает поддерживать тесты чистыми и удобными для чтения.

Работа с моками и стабами

Для тестирования кода, который зависит от внешних ресурсов (например, базы данных, API), можно использовать мок-объекты и стаб-методы. Это позволяет изолировать тестируемую логику от внешних зависимостей.

Для мокирования зависимостей удобно использовать такие библиотеки, как Sinon. Она позволяет создавать моки, шпионы и стабов для функций и методов.

Пример использования Sinon:

npm install sinon --save-dev

Пример создания мока с Sinon:

const sinon = require('sinon');
const math = require('../math');
const chai = require('chai');
const expect = chai.expect;

describe('Математические операции с моками', function() {
  it('должно использовать мок для вызова функции', function() {
    const mock = sinon.mock(math);
    mock.expects('add').once().withArgs(2, 3).returns(5);

    const result = math.add(2, 3);
    expect(result).to.equal(5);

    mock.verify(); // проверка, что ожидаемый вызов был сделан
  });
});

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

Тестирование с покрытием

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