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

Базовое тестирование

Есть много способов справиться с тестированием веб-приложений. С одной стороны, вы можете использовать некоторые инструменты на основе селена (или любую альтернативу) для автоматизации браузера, выполнения определенного набора сценариев и оценки ожидаемые результаты. С другой стороны, вы можете использовать более простой http-клиент (например, curl или помощники Node.js, такие как request, got или superagent) и проанализируйте ответы.

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

Когда проект стартовал, был создан первоначальный — чтобы не сказать базовый — тест путем создания небольшого веб-сайта, иллюстрирующего большинство функций. Во-первых, смесь различных обработчиков и сопоставлений была объединена в файле mappings.json. Затем два файла расширения выставили это определение через http и https.

Исходные сопоставления, использованные для создания прототипа REserve

  • Первое сопоставление — это типичный прокси, который разрешает любой запрос на удаленном веб-сайте.
  • Второе (и третье) сопоставление использует настраиваемый обработчик с группой захвата.
  • Последний обработчик сопоставляет оставшиеся запросы с файловой системой.

Файл http.json, используемый для отображения сопоставлений через http

Наконец, была разработана веб-страница для использования различных сопоставлений, и результат был проверен с помощью списка утверждений (спасибо помощнику gpf-js http).

Базовые тесты, выполняемые в браузере

Однако это вряд ли можно автоматизировать (или ленивый я не хотел переходить на селен).

Именно по этой причине была введена командная строка Node.js all.js.

Он запускает различные файлы конфигурации (http и https), создавая дочерний процесс с child_process.fork. Он использует функцию уведомления родительского процесса REserve для ожидания запуска сервера. После синхронизации он выполняет все утверждения, а затем останавливает сервер (уничтожая процесс).

Углубленное тестирование

Предыдущий подход рассматривает весь проект как автономный — монолитный — компонент и тестирует его, используя клиент. Это также известно как сквозное тестирование. Если вы понимаете пирамиду тестов, то эта категория тестов находится чуть ли не на вершине… То есть это должно быть место, куда прикладывается минимум усилий.

Упрощенная версия пирамиды тестов

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

мокко

Если вы знакомы с mocha framework, вы знаете, что он прост в реализации, широко используется и поддерживает асинхронные функции, такие как промисы.

Логотип платформы Mocha

Для каждого исходного файла проекта создается соответствующий тестовый файл, например: handlers/custom.js тестируется tests/mocha/handlers/custom.test.js. Структура каталогов также воссоздается в папке тестов мокко.

Этот шаблон упрощает настройку mocha, так как вам просто нужно настроить шаблон файла спецификации на *.test.js.

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

Отрывок казни мокко

Коротко об изоляции

Как объяснялось ранее, проект не начинался с сначала тесты. В результате инкапсуляция не выполнялась, а код сильно зависит от собственных API-интерфейсов Node.js. Особенно :

Возможна замена любых модулей Node.js (включая нативные) с помощью mock-require. Этот простой API позволяет вам предопределить модуль с фиктивной версией. Следовательно, всякий раз, когда используется API, возвращается фиктивный объект.

Издевательство над файловой системой

Имитация файловой системы на самом деле не является обязательной: может быть достаточно использования выделенной структуры каталогов в проекте.

Однако проект предназначен для работы на любой платформе. И действительно, среда разработки (Windows) отличается от среды непрерывной интеграции (Linux).

Различия файловых систем между операционными системами оказывают значительное влияние на REserve. Действительно, веб-сервер, работающий в UNIX-подобной операционной системе, будет чувствителен к регистру в URL-адресах. В Windows это может быть не.

Поскольку REserve использует только подмножество API-интерфейсов fs, была создана пользовательская фиктивная версия для переопределения только реально используемых API-интерфейсов.

Вся файловая система виртуализирована со словарем, членами которого являются объекты, представляющие либо файлы (если они содержат свойство content), либо папки (если content не найдено) .

Конкретный API управляет зависимостью файловой системы от регистра.

Основная функция виртуальной файловой системы

Насмешка над http, запросами и ответами

Согласно REserve, отличий между модулями http и https не так много. На самом деле используются только два метода:

  • createServer для запуска сервера HTTP(s)
  • запрос для пересылки входящего запроса на удаленный URL-адрес (используется обработчиком url)

Поскольку эти модули широко используются, их повторное тестирование бесполезно. Точно так же мы хотим упростить тесты и избежать использования слоя http(s).

Как результат :

  • createServer API сводится к одному условию, которое при необходимости вызывает ошибку.
  • API скопирует содержимое запроса в ответ.

А чтобы включить тестирование отдельных обработчиков, REserve предоставляет два класса для моделирования объектов запроса и ответа. Оба они реализуют потоки.

Реализации можно найти в:

Эти классы являются частью модуля NPM вместе с фиктивным помощником: он обеспечивает простую среду тестирования для разработки новых пользовательских обработчиков.

Качественные инструменты

Как убедиться, что код поддается сопровождению? Сколько тестов необходимо, чтобы убедиться, что код работает должным образом?

Для ответа на эти вопросы доступны различные инструменты.

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

Например :

if (parameter = '--config') {
  return false
}

Пример ошибочного кода

> standard --fix
standard: Use JavaScript Standard Style (https://standardjs.com)
  .\reserve\index.js:13:9: Expected a conditional expression and instead saw an assignment.
  .\reserve\index.js:13:9: Unexpected constant condition.

Вывод линтера

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

В проекте REserve используется стандартный JS, линтер на основе ESLint с предопределенной конфигурацией.

Покрытие кода Стамбулом

Один из способов проверить, являются ли тесты релевантными, — это определить количество сколько строк кодовой базы выполняется во время тестов. Эта операция называется измерением покрытия кода.

100% парадокс

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

Рассмотрим следующую функцию:

function divide (a, b) {
  return a / b;
}

Пример функции для тестирования

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

assert.strictEqual(divide(4,2), 2)

Пример теста

Поскольку мы достигли 100% охвата, означает ли это, что функция полностью протестирована?

На самом деле, нет. Это действительно зависит от спецификации функции.

Например, тест не дает ответов на следующие вопросы:

  • Что будет, если разделить на 0?
  • Какой результат вы ожидаете при вычислении divide(1, 3) * 3 ?
  • Что произойдет, если вы передадите параметры, которые не являются числами?

Короче говоря, 100% охват не гарантирует, что все протестировано, а наоборот, если не достигает 100% охвата, означает, что некоторые части не тестировались.

Инструменты

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

После выполнения тестов инструмент создает отчет, который содержит:

  • Файлы, которые были загружены
  • Строки, которые были выполнены

И в зависимости от детализации:

  • Функции, которые были вызваны
  • Ветви, которые были оценены (не все инструменты предоставляют эту информацию)

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

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

REserve использует, что само по себе зависит / является развитием Стамбул. Весь процесс прост, поскольку nyc поддерживает выполнение внешней команды и заботится обо всем прозрачно. Следовательно, покрытие кода запускается с помощью nyc mocha.

--------------------------|---------|---------|----------|---------|
File                      | % Stmts | % Branch | % Funcs | % Lines |
--------------------------|---------|---------|----------|---------|
All files                 |     100 |      100 |     100 |     100 |
 reserve                  |     100 |      100 |     100 |     100 |
  body.js                 |     100 |      100 |     100 |     100 |
  checkMethod.js          |     100 |      100 |     100 |     100 |
  configuration.js        |     100 |      100 |     100 |     100 |
  dispatcher.js           |     100 |      100 |     100 |     100 |
  iconfiguration.js       |     100 |      100 |     100 |     100 |
  index.js                |     100 |      100 |     100 |     100 |
  interpolate.js          |     100 |      100 |     100 |     100 |
  mapping.js              |     100 |      100 |     100 |     100 |
  mock.js                 |     100 |      100 |     100 |     100 |
  schema.js               |     100 |      100 |     100 |     100 |
  serve.js                |     100 |      100 |     100 |     100 |

Выдержка из отчета о покрытии

Непрерывная интеграция

Тесты, статические проверки и покрытие кода — хорошие способы оценить качество кода, но они работают только в том случае, если выполняются. Автоматизированный конвейер непрерывной интеграции гарантирует, что всякий раз, когда код помещается в репозиторий кода, эти инструменты выполняются.

REserve использует платформу Travis CI, и все эти инструменты запускаются во время сборки.

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

Код пахнет

И последнее, но не менее важное: проект также зарегистрирован на Code Climate.

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

Результат количественно обозначается значком, а также приблизительным временем уборки.

Вывод

В заключение следует отметить, что проект полностью протестирован, а его качество постоянно контролируется и измеряется. Но, тем не менее, его можно улучшить. Например, в отношении управления проектами не существует никаких историй или критериев приемки. Также качество тестов можно оценить с помощью мутационного тестирования.