Модульное тестирование с помощью Mocha | OTUS
⚡ Подписка на курсы OTUS!
Интенсивная прокачка навыков для IT-специалистов!
Подробнее

Курсы

Программирование
iOS Developer. Professional Kotlin Backend Developer Flutter Mobile Developer Symfony Framework C++ Developer. Basic Unity Game Developer. Basic Java Developer. Professional
-35%
Highload Architect Unity Game Developer. Professional React.js Developer Специализация Java-разработчик
-25%
Алгоритмы и структуры данных
-16%
Scala-разработчик C# Developer. Professional
-23%
Разработчик голосовых ассистентов и чат-ботов Team Lead Архитектура и шаблоны проектирования NoSQL Web-разработчик на Python Golang Developer. Professional PostgreSQL Vue.js разработчик Супер-практикум по использованию и настройке GIT Разработчик IoT Подготовка к сертификации Oracle Java Programmer (OCAJP) Программист С HTML/CSS
Инфраструктура
Инфраструктурная платформа на основе Kubernetes Microservice Architecture Базы данных Highload Architect Reverse-Engineering. Professional
-8%
Network engineer. Basic Administrator Linux.Basic MongoDB Infrastructure as a code MS SQL Server Developer Cloud Solution Architecture Мониторинг и логирование: Zabbix, Prometheus, ELK Супер-практикум по использованию и настройке GIT Разработчик IoT Экcпресс-курс «ELK» Супер-интенсив "Tarantool" Экспресс-курс «CI/CD или Непрерывная поставка с Docker и Kubernetes» Экспресс-курс «Введение в непрерывную поставку на базе Docker»
Корпоративные курсы
Безопасность веб-приложений Экосистема Hadoop, Spark, Hive Пентест. Практика тестирования на проникновение Node.js Developer Java QA Engineer. Basic
-18%
Reverse-Engineering. Professional
-8%
DevOps практики и инструменты NoSQL Reverse-Engineering. Basic Cloud Solution Architecture Внедрение и работа в DevSecOps Супер-практикум по работе с протоколом BGP Game QA Engineer Супер - интенсив по Kubernetes Дизайн сетей ЦОД Экспресс-курс «IaC Ansible» Экспресс-курс по управлению миграциями (DBVC) Экспресс-курс "Версионирование и командная работа с помощью Git" Основы Windows Server
Специализации Курсы в разработке Подготовительные курсы Подписка
+7 499 938-92-02

Модульное тестирование с помощью Mocha

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

Несколько слов о тестируемом приложении

Для примера возьмём React-приложение Calculator. Оно имеет два юнит-компонента: keypad и display. Это точно юниты, не зависящие от других юнитов. Кроме того, компоненты разделены на презентационные (уже упомянутые display и keypad) и компоненты-контейнеры — calculator-app — единственный компонент, имеющий state, и определяющий, что отображается на экране при нажатии на кнопку.

Но вышеописанный компонент отвечает только за логику отображения, а что насчёт вычислений? Ими занимается отдельный модуль calculator, не имеющий React-зависимостей. И такой модуль прекрасно подходит для юнит-тестирования, т. к. не содержит I/O- и UI-зависимостей.

Что касается отделения логики калькулятора от компонента React, то это было сделано путём выделения логики в модуль calculator. Это простейший модуль, принимающий состояние калькулятора (объект), а также символ (цифру либо оператор). И, разумеется, возвращающий новое состояние калькулятора. Но если каждое состояние зависит от предыдущего, как получить самое первое состояние? Довольно просто — модуль экспортирует initialState, которое вы применяете для инициализации. То есть состояние калькулятора не является неизвестным, а включает в себя поле display, которое и надо показать приложению калькулятора для данного состояния.

Вот, например, начало кода:

module.exports.initialState = { display: '0', initial: true }

module.exports.nextState = (calculatorState, character) => {
  if (isDigit(character)) {
    return addDigit(calculatorState, character)
  } else if (isOperator(character)) {
    return addOperator(calculatorState, character)
  } else if (isEqualSign(character)) {
    return compute(calculatorState)
  } else {
    return calculatorState
  }
}

//....

Здесь не так важна специфика алгоритма, как простота функции, которую экспортирует наш модуль, ведь, получив состояние, мы можем всегда проверить следующее.

Приступим к тестированию

По большему счёту, все тестирующие фреймворки похожи: вы пишете тестовый код в функциях, а фреймворк их запускает. Причём конкретный код, выполняющий запуск, как правило, называют «runner».

Что касается Mocha, то здесь «Runner» представляет собой скрипт под названием mocha. Его можно легко увидеть, посмотрев на package.json в тестовом скрипте:

"scripts": {
...
    "test": "mocha 'test/**/test-*.js' && eslint test lib",
...
},

Это обеспечит запуск всех тестов в тестовой папке, названия которых начинаются с префикса test-. При запуске вы увидите приблизительно такой результат:

1_ZCXpZVRMgzZsCnaQMRZO4Q_1-20219-eeb47f.png

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

const {describe, it} = require('mocha')
const {expect} = require('chai')
const calculator = require('../../lib/calculator')

describe('calculator', function () {
  const stream = (characters, calculatorState = calculator.initialState) =>
    !characters
      ? calculatorState
      : stream(characters.slice(1),
               calculator.nextState(calculatorState, characters[0]))

  it('should show initial display correctly', () => {
    expect(calculator.initialState.display).to.equal('0')
  })
  it('should replace 0 in initialState', () => {
    expect(stream('4').display).to.equal('4')
  })
//...

Давайте первым делом импортируем mocha и библиотеку для проверок (assert’ов) expect. И выполним импорт нужных нам функций: describe, it, except. Далее выполним импорт тестируемого модуля — calculator.

Потом пойдут тесты, описанные с помощью функции it, допустим:

it('should show initial display correctly', () => {
    expect(calculator.initialState.display).to.equal('0')
})

Функция принимает строку, которая описывает тест, и функцию, которая и является непосредственно самим тестом. Однако it-тесты не могут быть «голыми», а должны быть в тестовых группах, определяемых посредством функции describe.

Что же находится в тестовой функции? На самом деле, всё, что мы пожелаем. В нашем случае мы проверяем, что исходное состояние display равняется нулю. Но как мы это выполняем? Ведь мы могли бы сделать что-то типа этого:

if (calculator.initialState.display !== '0')
  throw 'failed'

И такое решение бы подошло. Тест в Mocha не срабатывает, когда генерирует исключение, и это довольно просто. Однако expect делает тест намного приятнее, ведь в функции есть много фич, которые облегчают тестирование данных — к примеру, можно проверить, что массив либо объект равны конкретному значению.

В этом и заключается суть модульного тестирования: — запуск функции либо набора функций (или создание экземпляра объекта с последующим вызовом некоторых его методов, если мы говорим об ООП); — сравнение фактического результата и ожидаемого результата.

Источник: "Testing Your Frontend Code: Part II (Unit Testing)".

Не пропустите новые полезные статьи!

Спасибо за подписку!

Мы отправили вам письмо для подтверждения вашего email.
С уважением, OTUS!

Автор
0 комментариев
Для комментирования необходимо авторизоваться