Pull to refresh

PhantomJS + JSCoverage + QUnit или консольные JS юнит-тесты с подсчетом покрытия

Reading time 4 min
Views 6K
Поговорим о случае, когда нужно автоматизировать запуск тестов и сбор статистики покрытия, к примеру, для гипотетической клиентской JS библиотеки. Задача не совсем тривиальна, поскольку для нормальной работы библиотеки требуется полноценный браузер — библиотека является визуальной оберткой над стандартными компонентами формы. Библиотека должна быть написана так, чтобы все взаимодействие с ее объектами можно было производить с помощью методов, которые они предоставляют, а не только через непосредственные манипуляции с DOM (т.е. любое действие юзера может быть запущено не только событием, допустим, клика по чему-то, но и руками через метод). Но тем не менее, надо этот DOM иметь, чтобы результаты работы методов помимо изменения внутреннего состояния объектов также отображались и в DOM. В целом напоминает приложения на Sencha (ExtJS).

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

Концепт

Один из вариантов решения — JSTestDriver, о котором здесь уже писали, но в рассматриваемом случае этот вариант не подошел, поскольку всё решение должно запускаться консольно, не должно плодить ни лишних сервисов, ни браузерных окон, должно запускаться и умирать сразу по завершении работы. Плюс на данный момент JSTestDriver не умеет исключать подключенные файлы из Coverage Report, что сильно искажает картину, т.к. считать покрытие, например, для подключенной jQuery или MooTools дело лишнее. На хабре был обзор простого запуска QUnit тестов с помощью PhantomJS, но без подсчета покрытия или сборки страницы (что является необходимым как раз таки для покрытия).

С учетом уточненных требований, родилось решение на основе связки PhantomJS + JSCoverage + QUnit, размещенное мной на Google Code. Остановимся подробнее на компонентах:
  • PhantomJS — консольный (безголовый) браузер, контролируемый через JS API;
  • JSCoverage — консольный парсер JS файлов, внедряет в них для каждой исполняемой строки инкремент соотв. элемента массива для подсчета количества выполнений. Есть незначительные ограничения — участвуют только строки, которые вообще можно выполнить, т.е. не комментарии, к примеру. Для нотаций объектов и массивов учитывается только строка, где нотация началась;
  • QUnit — небольшой JS фреймворк для удобного и быстрого создания юнит-тестов, в том числе асинхронных, запускается в браузере как страничка с подключенными скриптами.

Запуск

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

var config = {
    includes: [ // файлы, которые будут включены в запускаемый скрипт
        {
            file: 'lib/jquery-1.7.1.js',
            coverage: false // не включаем публичную либу в состав отчета о покрытии
        },
        {
            file: 'lib/json2.js',
            coverage: false
        },
        {
            file: 'lib/testable.js',
            coverage: true // а вот тестируемую библиотеку — включаем
        }
    ],
    testCases: [ // массив путей до тесткейсов, могут обрабатываться рекурсивно, включены будут только файлы, подходящие по маске
        {
            location: '/tests',
            pattern: /.+Test\.js/g,
            recursive: true
        }
    ],
    target: { // информация о сборочной директории
        location: '/target'
    }
};

После запуска «Самого Главного Батника» (в примере из репозитория run-tests.cmd или run-tests2.cmd в зависимости от того, какой набор планируется запускать) происходит, упрощенно, следующий ряд действий:
  1. Собрать в одну папку все подключаемые JS файлы для обработки JSCoverage'ом;
  2. Пройтись по ним JSCoverage'ом;
  3. Собрать ссылки на остальные подключаемые файлы, не участвующие в подсчете покрытия (библиотеки, сам QUnit, вспомогательные компоненты для тестирования и т.д.);
  4. Найти все файлы с тест кейсами;
  5. Собрать из описанных выше элементов страницу для выполнения в обычном для QUnit порядке;
  6. Запустить эту страницу со скриптами на выполнение из-под PhantomJS;
  7. Забрать из «окна юраузера» отчет QUnit и статистику выполнения — покрытие, кол-во выполненных, успешных и упавших тестов;
  8. Сгенерировать из всего этого отчет в человекопонятном виде;
  9. Сложить в папку отчеты, а также все необходимое для повторного запуска.

Отчеты

После проделанных манипуляций в папке с утилитой окажется подпапка /target/, в которой будут сложены:
  • test.html — та самая страница с нужным списком скриптов для запуска в webkit-подобных браузерах (ограничение PhantomJS, ему пока нельзя давать ссылки с протоколом file://), позволяет воспользоваться всем любимым функционалом dev tools для отладки кривых тестов в привычной визуальной среде (порядок такой — прогоняем консольный тест, смотрим в браузере, фиксим, прогоняем снова, смотрим в браузере обновленный вариант);
  • test-result.html — отчет о выполнении тестов, собранная статистика покрытия, без непосредственного выполнения тестов:
  • *.js.html — отчеты покрытия по каждому включенному в отчет файлу:
  • coverage.json — сырая статистика количества исполненных строк по файлам, просто на всякий случай посмотреть, что собрал JSCoverage.

Итог

+ Сбор статистики покрытия;
+ Автоматическая сборка ресурсов для проведения тестов, от пользователя требуется один раз сконфигурировать и просто запускать батник;
+ Запуск из-под консоли;
+ Standalone (для запуска не надо ничего, кроме двух программ, которые не надо конфигурировать или устанавливать — просто распаковать архивы);
+ Наглядный отчет после выполнения;
­− Тестирование происходит в условиях webkit браузера, что не позволяет проверить, например, особенности работы браузеров с массивами, с другой стороны кроссбраузерные тесты лучше гонять чем-то наподобие Selenium'а, чтобы эмулировать действия юзера, в случае рассматриваемого тула идет чисто тесты API;
­− Сборщик на данный момент работает только с относительными путями, в ближайшее время появится поддержка абсолютных путей и ссылок;
­− Нет интеграции с Maven или чем-то другим для непрерывной интеграции — в ближайших планах.

На данный момент утилиту можно рассматривать как proof of concept, который неплохо справляется со своей задачей, упрощает жизнь, но которая не лишена и недостатков. В любом случае я планирую развивать функционал по мере необходимости и по возможности. В комплекте идет также небольшая утилитка для запуска тестов от JSTestDriver в рамках описанного фреймворка, так что Вы можете гонять тесты и в IDE в PhantomJS'е, но на данный момент она не умеет запускать асинхронные тесты.
Tags:
Hubs:
+26
Comments 12
Comments Comments 12

Articles