Пользователь
0,0
рейтинг
24 марта 2014 в 04:10

Разработка → Gremlins.js — monkey testing библиотека для веб приложений перевод tutorial

NPM version

Это первая из двух статей, рассказывающая о тестировании с помощью gremlins.js и grunt-gremlins. Первая статья — перевод официальной документации gremlins.js. Вторая — опыт внедрения gremlins.js в реальный проект при помощи grunt-gremlins.

Gremlins.js это monkey testing библиотека написанная на JavaScript, для Node.js и браузеров. С ее помощью проверяется надежность веб-приложений под полчищем гремлинов.

Kate: What are they, Billy?
Billy Peltzer: They're gremlins, Kate, just like Mr. Futterman said.


image


Цель



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

Gremlins.js эмулирует случайные действия пользователя: гремлины кликают везде, куда могут добраться, вводят случайные данные в формы, или перемещают мышь над элементами, которые этого не ожидают. Их цель: вызвать JavaScript ошибку или заставить приложение выйти из строя. Если им это не удалось, поздравляю! Приложение достаточно пуленепробиваемо для того, чтобы показать его реальным пользователям.

Эта практика так же известна как Monkey testing или Fuzz testing, она широко распространенна в мире мобильной разработки (посмотрите на Android Monkey program). Сегодня, когда интерфейс (MV*, d3.js, Backbone.js, Angular.js, etc.) и бекенд (Node.js) разрабатывается полностью на JavaScript, эта технология становится применима и для веб приложений.

Базовое использование



Полчище гремлинов (horde) — это армия из специализированных гремлинов, готовых встряхнуть ваше приложение. Выпустите (unleash) их для начала стресс тестов:

var horde = gremlins.createHorde()
horde.unleash();
// гремлины будут действовать случайно, с периодичностью в 10ms, 100 раз


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

Вы можете наблюдать за их поведением в окне браузера (они оставляют за собой следы) или отслеживать логи в консоли:

gremlin formFiller input 5 in <input type=​"number" name=​"age">​
gremlin formFiller input pzdoyzshh0k9@o8cpskdb73nmi.r7r in <input type=​"email" name=​"email">​
gremlin clicker    click at 1219 301
gremlin scroller   scroll to 100 25
...


Кроме того, существуют безвредные могваи (mogwais). Могваи только наблюдают за активностью приложения и записывают дынне в лог. Для примера, «fps» могвай каждые 500ms показывает количеcтво кадров в секнду (FPS).

mogwai  fps  33.21
mogwai  fps  59.45
mogwai  fps  12.67
...


Иногда могваи сообщают, когда гремлинам все же удалось навредить приложению. К примеру, если fps опустится ниже отметки в 10, fps могвай выведет ошибку в лог:

mogwai  fps  12.67
mogwai  fps  23.56
err > mogwai  fps  7.54 < err
mogwai  fps  15.76
...


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

Гремлины, как и могваи — это простые JavaScript функции. Если gremlins.js не предоставляет необходимых вам гремлинов, вы довольно просто можете реализовать их самостоятельно:

// добавляем нового гремлина, который вызывает метод .blur() на активном элементе
horde.gremlin(function() {
  document.activeElement.blur();
});


Загляните в папку с примерами, чтобы лучше понять как работает gremlins.js.

Вы можете сконфигурировать любой компонент в gremlins.js; расширяйте функциональность и адаптируйте ее для своих сценариев.

Установка



В браузере, файл gremlins.min.js может быть добавлен как сторонняя библиотека, после чего gremlins будет доступен в глобальном пространстве имен:

<script src="path/to/gremlins.min.js"></script>
<script>
gremlins.createHorde().unleash();
</script>


Есть возможность подключить gremlins.min.js как RequireJS модуль, не засоряя глобальное пространство имен:

require.config({
  paths: {
    gremlins: 'path/to/gremlins.min'
  }
});

require(['gremlins'], function(gremlins) {
  gremlins.createHorde().unleash();
});


Продвинутое использование



Настройка гремлинов и могваев для использования в тестах



Изначально все гремлины и могваи уже добавлены в полк (horde).

Вы так же можете выбирать и добавлять только необходимых вам гремлинов с помощью метода gremlin() у объекта horde:

gremlins.createHorde()
  .gremlin(gremlins.species.formFiller())
  .gremlin(gremlins.species.clicker().clickTypes(['click']))
  .gremlin(gremlins.species.scroller())
  .gremlin(function() {
    window.$ = function() {};
  })
  .unleash();


Для того, чтобы добавить ваших собственных гремлинов к стандартным, воспользуйтесь методом allGremlins():

gremlins.createHorde()
  .allGremlins()
  .gremlin(function() {
    window.$ = function() {};
  })
  .unleash();


Чтобы добавить могваев, используйте методы mogwai() и allMogwais() таким же образом.

На данный момент gremlins.js поставляет несколько гремлинов и могваев:

  • clickerGremlin кливает на все видимые зоны документа
  • formFillerGremlin заполняет формы вводя данные в инпуты, выбирая селекторы, чекбоксы и т.д
  • scrollerGremlin занимается скроллингом viewport'a
  • typerGremlin нажимает клавиши на клавиатуре
  • alertMogwai предотвращает блокирование тестов при вызове alert()
  • fpsMogwai логирует количество кадров в секунду (FPS) в браузере
  • gizmoMogwai может остановить разбушевавшихся гремлинов


Конфигурация гремлинов



Все гремлины и могваи поставляемые в gremlins.js являются настраиваемыми функциями (configurable functions), то есть вы можете изменить логику работы их методов.

Для примера, гремлин clicker — это функция, возвращающая объект, который вы можете вызвать напрямую:

var clickerGremlin = gremlins.species.clicker();
clickerGremin(); // вызывает случайное событие мыши


Гремлин clicker имеет следующие методы для кастомизации:

gremlins.species.clicker()
  .clickTypes(['click']) // какие типы событий мыши будут вызваны
  .canClick(function(element) {
    // кликать только элементы находящиеся в bar
    return $(element).parents('#bar').length;
    // когда canClick вернет false, гремлин будет искать другой элемент
    // чтобы кликнуть, пока maxNbTries не будет достигнут
  })
  .showAction(function(x, y) {
    // по умолчанию гремлин clicker отображает это действие в виде красного круга
    // переопредение showAction() пустой функцией сделает действия гремлина невидимыми
  })


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

Больше информации о конфигурируемых функциях ищите в статье о service closures.

Поддержка Random Seed



Если вы хотите, чтобы ваши атаки можно было повторить, вам необходимо инициализировать генератор случайных чисел. Gremlins.js использует Chance.js для генерации случайных данных, таким образом его можно инициализировать:

// seed the randomizer
horde.seed(1234);


Выполнение кода до или после атак



Вы можете исполнять произвольный код до начала тестирования. Обычно бывает полезно:

  • Запустить профайлер
  • Выключить какую либо функциональность для более эффективного тестирования
  • Инициализировать приложение


Для этого объект horde имеет метод before(), единственным аргументом принимающий callback:

horde.before(function startProfiler() {
  console.profile('gremlins');
});


Для очистки тестового окружения, объект horde так же предоставляет метод after():

horde.after(function stopProfiler() {
  console.profileEnd();
});


Оба метода поддерживают асинхронный вызов callback'a:

horde.before(function waitFiveSeconds(done) {
  window.setTimeout(done, 5000);
});


Стратегия



По умолчанию гремлины будут атаковать ваше приложение в произвольном порядке разделенные промежутком в 10ms. Эта стратегия атаки называется distribution. Изменить ее можно используя метод horde.strategy():

horde.strategy(gremlins.strategies.distribution()
  .delay(50) // ждать 50ms перед началом атаки
  .distribution([0.3, 0.3, 0.3, 0.1]) // первые три гремлина имеют больше шансов быть вызванными чем последний
)


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

Остановка тестирования



Остановить атаку в случае возникновения чрезвычайной ситуации можно с помощью метода horde.stop(). Gizmo использует этот метод для предотвращения последующей атаки на приложение после 10 ошибок. Вы так же можете использовать этот метод, если не хотите чтобы нападение продолжилось.

Модификация логирования



По умолчанию, gremlins.js выводит в консоль все действия гремлинов и наблюдения могваев. Если для вас предпочтительней использовать альтернативный метод журналирования (к примеру, хранить активность гремлинов в localStorage и отправка их каждые 10 секунду c помощью AJAX), просто передайте объект logger с четырьмя методами (log, info, warn, и error) в метод logger():

var customLogger = {
  log:   function(msg) { /* .. */ },
  info:  function(msg) { /* .. */ },
  warn:  function(msg) { /* .. */ },
  error: function(msg) { /* .. */ }
};
horde.logger(customLogger);


Вместо создания собственного логгера, посмотрите в сторону Minilog

Ссылки



Перевод: Francois Zaninotto
Alexey Kupriyanenko @Upward
карма
20,2
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (13)

  • +12
    Люблю подобный нейминг :)
  • 0
    Нужно добавить опцию bgm, при включении которой на фоне тестов будет играть это — pleer.com/tracks/8023316PMEO
    • 0
      в пещере горного короля. и увеличивать скорость и количество нажатий
  • +3
    Вот так уедешь в отпуск, а они напишут Войну и мир.
    • +3
      Иногда наталкиваюсь на некоторые произведения при чтении которых складывается впечатление, что гремлины уже давно заняты сочинительством.
      • 0
        Главное, чтобы эти гремлины не захватили ваше приложение.
  • 0
    А что с переходами между страницами? У меня есть сайт, который косит под веб-приложение, но возможны выходы (и переходы внутри) по href. Библиотека под такое заточена? Лог ошибок единый или сбросится при покидании страницы (имеется в виду имплементация по умолчанию)?
    • +2
      У себя решил эту проблему переопределением метода, который отвечает за переходы по страницам, и теперь в тестовом энвайроменте редирект в принципе не возможен. По умолчанию библиотека под это не заточена, и лог сбрасывается перед каждым запуском тестов (в вашем случае при переходам по страницам).

      Как решение могу предложить переопределить объект логера, и сохранять лог например в localStorage, тогда при завершении тестов, сможете лог достать оттуда.

      Второй вариант — запускать тесты в фантоме с помощью grunt-gremlins, где есть доступ к файловой системе. Сейчас логирования в файл еще нет, но появится в ближайшее время, так же в планах удобный менеджмент логирования для разных подзадач.
      • 0
        Спасибо за ответ, попробую использовать скрипт. Наверное, сначала тупо погоняю одностраничные приложения, из которых состоит сайт, запретив переход по href в тестовом окружении, как Вы и написали.
  • 0
    Пищу )
  • 0
    Поясните пожалуйста, каким образом генерируется дефолтное событие клика на элементе? Или библиотека парсит мой код, вытаскивает все функции и целенаправленно вызывает callback`и?
    • +1
      Библиотка не знает ничего о вашем коде, событие клика генерируется слчайным образом, с помощью объекта, полученного вызовом document.createEvent("MouseEvents"). Это значит, что эффект будет примерно тот же, что и от случайного клика (или dblclick, mousedown и т.д.) реальной мышью пользователя в какой либо участок экрана.

      Вы можете сконфигурировать этого гремлина, указав в какую именно область экрана гремлин должен кликать (метод positionSelector), с какими именно элементами он может работать (canClick) и какие типы эвентов он должен генерировать (см. по умолчанию)
      • 0
        На самом деле document.createEvent(«MouseEvents») не всегда сможет эмулировать действия пользователя. Например, клик внутри ифрейма не прокатит (если у вас, конечно, нет доступа к его document). Или вам такие образом не обмануть мобильный браузер, чтобы автоматом запустить, к примеру, HTML5 video. Думаю, что есть еще достаточное количество ситуаций, когда document.createEvent(«MouseEvents») будет бессилен эмулировать действия человека.
        Но, тем не менее, мне эта свора нравится.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.