четверг, 26 ноября 2009 г.

Модульное тестирование javascript кода при помощи JsTestDriver

Бочка мёда

Хочу порекомендовать JsTestDriver - великолепный фрэймворк для модульного тестирования (unit testing) javascript кода от ребят из Google. Он позволяет в считанные доли секунды протестировать javascript-код одновременно на любом (ну, почти любом) количестве любых браузеров с любых компьютеров и платформ. Впечатляет, не правда ли?

Идея JsTestDriver проста, как всё гениальное (картинка взята с оф. сайта):


Запускается небольшой веб-сервер, причем не обязательно его запускать на локальной машине. К нему, как и к обычному веб-серверу, используя определённый URL (например, http://localhost:4224/capture), коннектятся необходимые для тестирования браузеры, которые могут находится на любом компьютере (и, соответственно, платформе), с которого доступен сервер. Таким образом, можно будет одновременно тестировать код на Safari под Mac OS, Internet Explorer под Windows и, например, Firefox под Linux.

Далее происходит основная магия.
Браузеры (slaves в терминологии JsTestDriver) начинают периодически опрашивать сервер (при помощи AJAX) в ожидании новых задач (тестов). И, как только задание будет получено, браузеры загрузят необходимые скрипты, выполнят тестовые функции (test cases) и вернут на сервер результаты выполнения. Управление же сервером происходит при помощи клиентского приложения, которое легко интегрируется как с IDE разработчика, так и с системами автоматической сборки проектов (Ant, Team City, Phing и т.п.).

Однако, разработчику важна не столько вся эта кухня, сколько возможность иметь под рукой удобный инструмент для лёгкого и быстрого запуска модульных тестов и отслеживания результатов. В этом нам поможет JsTestDriver плагин для Eclipse (аналогичный плагин есть так же и для IntelliJ IDEA).



Не вдаваясь в подробности опишу лишь основные фичи этого плагина:
  • Минимум настроек: только номер порта для сервера и пути к файлам браузеров (Firefox, Chrome, Safari, Internet Explorer и Opera) на локальном компьютере
  • Запуск сервера и браузеров для тестирования прямо из IDE
  • Простейший конфигурационный файл для запуска тестов (прописывается только URL тестового сервера и список необходимых javascript-файлов)
  • Ручной запуск модульных тестов через меню Run
  • Автоматический запуск модульных тестов при каждом изменении javascript-файлов
  • Наглядное отображение результатов тестирования прямо в IDE (на каком браузере под какой платформой в каком тест-кейсе произошла ошибка)
В общем, установка и настройка JsTestDriver не вызывают никаких особых проблем (всё очень подробно описано на оф. сайте), а уж использование приносит только сплошное удовольствие. Правда, если быть честным, для этого пришлось немного (совсем чуть-чуть :) "поработать напильником"...

Капля дёгтя

Дело в том, что текущая версия (1.2 для сервера и 1.0.6 для плагина) немного недоработана (уверен, что это не надолго). В частности, если в каком либо тестируемом js-файле будет синтаксическая ошибка (или иная ошибка, возникающая при исполнении этого файла), то в результатах тестов это никак не отражается. Кроме того, наблюдается некоторая глючность Opera при исполнении тестов.

Лекарство

Для решения проблемы пришлось переписать один метод по загрузке скриптов и добавить "системный" тест-кейс, который будет отражать ошибки, произошедшие до начала выполнения пользовательских тест-кейсов (см. runner-fix.js). Ну и, в дополнение, мне показалось уместным добавить ещё две вещи:
  1. Обновление тестовой страницы после выполнения тестов, чтобы исключить возможность влияния предыдущего выполнения тестов на последующие
  2. assertFail( [expectedErrorMessage], caseWrapper ) - функция, которая позволяет протестировать случаи, когда должна происходить ошибка. Пример использования:
      function doSomething() {
          throw new Error( 'Some error' );
      }
      ...
    
      // Test case
      assertFail( 'Some error', function(){ doSomething() } );
      // true
      
Чтобы внедрить эти изменения в JsTestDriver нужно выполнить следующие шаги:
  1. Загружаем архив (содержит три файла: runner-fix.js, Runnerquirks.html, Runnerstrict.html)
  2. Находим JsTestDriver.jar из которого запускается сервер. Для плагина к Eclipse он находится где-то в папке configuration. В частности у меня, вот тут:
    c:\Program Files\Eclipse\Galileo\configuration\org.eclipse.osgi\bundles\929\1\.cp\lib\
  3. Открываем JsTestDriver.jar как обычный zip-архив
  4. Заходим в папку JsTestDriver.jar\com\google\jstestdriver\javascript\
  5. Копируем туда файлы из runner-fix.zip
  6. Запускаем JsTestDriver (вручную или через Eclipse плагин) и наслаждаемся :)
Подробнее о том, как собственно устанавливать, настраивать и использовать сервер или плагин, или писать тест-кейсы, смотрите по ссылкам, приведенным ниже. Там же можно найти общую информацию о тестировании вообще и о модульном тестировании в частности.

На последок хочется отметить, что разработчики JsTestDriver надеятся, что javascript сообщество объединится в поддержку этого фрэймворка, как единого движка для запуска тестов (наподобие JUnit в Java). Что, совместно с использование различных расширений (например, для YUI Test или QUnit), сделает процесс модульного тестирования javascript максимально продуктивным.

Что ж, кажется JsTestDriver этого вполне достоин.


Ссылки по теме:

пятница, 31 июля 2009 г.

Тюнинг code completion в Spket IDE

Spket IDE — отличная среда для современной сложной JavaScript-разработки (подробнее по ссылкам ниже [^]), однако, по непонятным мне причинам, при работе на кастомном профайле (в настройках Эклипса Spket/JavaScript Profiles) в code completion отсутствуют некоторые свойства стандартных объектов (например, методы match, replace, search и split для String). Причем, добавить их через подключение js-файла в кастомный JavaScript-профайл тоже не получается.

Решить проблему можно следующим образом (на примере плагина под Эклипс):
  1. Выходим из Эклипса (если он запущен)
  2. Заходим в папку plugins Эклипса
  3. При помощи любого файлового менеджера (FAR, Total Commander) открываем архивный файл com.spket.js_Х.Х.Х.jar (где X.X.X — ваша версия плагина Spket IDE)
  4. Редактируем файл config/core.js, добавляя недостающие свойства
Синтаксис там очень простой:
...

class Number {
    static var MAX_VALUE:Number;
    static var MIN_VALUE:Number;
    ...
}

class String {
    var length:Number;

    static function fromCharCode(... chars):String;

    function String(string:String);
    function charAt(index:Number):String;
    ...

    function match(searchValue:RegExp_or_String):Array;
    function replace(searchValue:RegExp_or_String, replaceValue:String_or_Function):String;
    function search(searchValue:RegExp_or_String):Number;
    function split(separator:String, limit:Number):Array;
}

class RegExp {
    function RegExp(pattern:String, flags:String);
    ...
}

...
так что проблем особых возникнуть не должно. После перезаргузки Эклипса новые свойства (методы) станут доступны для code completion.


Ссылки по теме: