Это первая из двух статей, рассказывающая о тестировании с помощью 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.
Цель
Предвидите ли вы все необычные пользовательские сценарии при разработке 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
Ссылки
Автор: Upward