Давайте создадим систему для выполнения функциональных тестов в веб-приложениях, используя Selenium и PhantomJS. Получившаяся система позволит нам писать простые тестовые сценарии на JavaScript и тестировать эти сценарии как в реальных браузерах, так и в симуляторе без головы.
Выбор компонентов
Очевидным недостатком Selenium является то, что для всех тестов требуется полный графический рабочий стол.
Для начала нам нужно выбрать элемент управления браузером или механизм эмуляции для симуляции конечного пользователя. Долгое время основным игроком на этом поле был Selenium , и он до сих пор есть. Selenium позволяет автоматизировать управление реальными браузерами в реальных операционных системах, что является его основным преимуществом: вы можете быть абсолютно уверены, что тесты представляют реальность настолько близко, насколько это возможно.
Очевидным недостатком Selenium является то, что для всех тестов требуется полный графический рабочий стол. В результате ваши тесты могут стать медленными. Однако Selenium может быть фантастическим, если у вас есть необходимые ресурсы для настройки виртуальных машин для разных операционных систем и их соединения.
На противоположном конце спектра находится PhantomJS : небольшой, но отличный проект, использующий движок WebKit с полным доступом к JavaScript, но без графической части. PhantomJS очень прост в настройке, работает на любой машине и работает значительно быстрее.
Selenium теперь может управлять PhantomJS так же, как и любой другой браузер.
PhantomJS, будучи полным WebKit, покрывает 90% ваших потребностей в функциональном тестировании. В конце концов, если ваше приложение работает в WebKit правильно, вполне вероятно, что оно будет работать правильно в других браузерах. Очевидно, что это исключает Internet Explorer 6–8 .
Однако, по мере того как ваш проект становится все более популярным, оставшиеся 10% становятся серьезной проблемой. Если ваш комплект функционального тестирования настроен непосредственно на PhantomJS, было бы непросто переписать тесты для Selenium.
К счастью, недавно, ближе к концу 2012 года , мы получили подарок в виде привязки PhantomJS к Selenium. Другими словами, Selenium теперь может управлять PhantomJS так же, как и любой другой браузер.
Учитывая, что сам Selenium не требует сложной настройки и может работать где угодно, мы можем использовать привязки Selenium для управления PhantomJS и покрывать 90% наших потребностей в тестировании. Если позже вам потребуется более мощное тестирование, вы можете настроить дополнительные подключения браузера к Selenium, не меняя ни одной строки в своем коде.
Таким образом, наш выбор для движка браузера — Selenium с PhantomJS .
Описание тестов
Selenium предлагает привязки на самых популярных языках программирования, поэтому мы можем выбрать язык в соответствии с нашими потребностями. Это, пожалуй, самая противоречивая часть этой статьи: я считаю, что JavaScript — лучший выбор для описания функциональных тестов для веб-сайтов и веб-приложений.
- Независимо от того, какую серверную технологию вы используете, ваш интерфейс всегда будет использовать JavaScript ( это применимо, даже если вы используете язык, который компилируется до обычного JavaScript, например CoffeeScript или TypeScript. ). Таким образом, JavaScript всегда будет понятным хотя бы для одного человека из вашей команды.
- Затем рассмотрите возможность написания ваших функциональных тестов непрограммистами. Популярность JavaScript во внешнем интерфейсе в сочетании с выразительностью в способности создавать понятные доменно-ориентированные языки явно позволяют большему количеству людей писать функциональные тесты.
- Наконец, вполне естественно управлять тестовым браузером с помощью JavaScript, учитывая, что он очень асинхронный, и это то, чем мы ежедневно управляем браузером.
Привязки Selenium для JavaScript называются webdriverjs . Хотя проект является менее зрелым, чем официально поддерживаемые драйверы для Java, C #, Ruby и Python, тем не менее он уже содержит большую часть необходимой нам функциональности.
Пробный запуск
Наконец, нам нужен тестовый прогон или приложение для запуска тестов по имени, и просто распечатать вывод, отметив, сколько тестов прошло успешно или не удалось. Этот организатор теста должен также предложить библиотеку утверждений, которая позволяет кодировщику выразить, если тест пройден успешно или не выполнен.
Выбор здесь абсолютно свободен. Существует множество тестов JavaScript, но для этой статьи был выбран Mocha с Chai . Mocha обеспечивает значительную гибкость, широкий выбор форматов вывода и популярный жасминоподобный синтаксис. Чай позволяет писать описательные BDD-подобные утверждения.
Настроить
Вот последний стек, который мы будем использовать:
- Мокко — тестовый бегун
- Чай — библиотека утверждений
- webdriverjs — привязки управления браузером
- Selenium — браузерная абстракция и запущенная фабрика
- PhantomJS — быстрый безголовый браузер
Node.js и npm
Поскольку большая часть нашего стека основана на JavaScript, нам нужны node.js и npm . Оба из них являются общими инструментами в сообществе, и я предполагаю, что вы уже настроили их. Если вы этого не сделаете, используйте установщик на сайте node.js. Не волнуйся; если что-то пойдет не так, в Интернете есть множество руководств по установке Node.
Мокко, чай и вебдрайверс
Все три из них могут быть установлены, используя npm
:
1
|
sudo npm install -g mocha chai webdriverjs
|
Кроме того, вы можете установить их локально в каталоге, где находятся ваши тесты:
1
|
npm install mocha chai webdriverjs
|
Селен
Скачать Selenium Server . Он распространяется в виде одного файла jar
, который вы запускаете просто:
1
|
java -jar selenium-server-standalone-2.28.0.jar
|
Как только вы выполняете эту команду, она загружает сервер, к которому ваш тестовый код будет подключаться позже. Обратите внимание, что вам нужно будет запускать Selenium Server при каждом запуске тестов.
PhantomJS
Быстрая версия
Используйте npm
для глобальной установки PhantomJS:
1
|
sudo npm install -g phantomjs
|
Другие опции
Нам нужна свежая версия PhantomJS — как минимум 1.8. Это означает, что пакеты, предоставляемые вашим менеджером пакетов ( apt-get
, MacPorts, …), скорее всего, будут устаревшими.
Вы можете установить, используя npm без глобальной установки, или используя другие методы вручную. В этом случае, однако, вам придется указывать Selenium, где вы разместили PhantomJS каждый раз, когда вы запускаете Selenium:
1
|
PATH=»/path/to/node_modules/phantomjs/bin:$PATH» java -jar selenium-server-standalone-2.28.0.jar
|
Объединяя все
Теперь, когда у нас есть все части, мы должны собрать все воедино.
Помните: перед запуском любых тестов вы должны запустить Selenium Server:
1
|
java -jar selenium-server-standalone-2.28.0.jar
|
Selenium будет управлять PhantomJS изнутри; вам не нужно беспокоиться об этом.
Теперь нам нужно подключиться к Selenium из нашего JavaScript. Вот пример фрагмента, который будет инициировать соединение с Selenium и иметь готовый объект для управления нашим экземпляром Selenium:
// Используйте webdriverjs для создания Selenium Client var client = require ('webdriverjs'). remote ({ требуемые возможности: { // Вы можете выбрать другие браузеры // http://code.google.com/p/selenium/wiki/DesiredCapabilities browserName: 'phantomjs' }, // у webdriverjs много выходных данных, которые обычно бесполезны // Однако, если что-то пойдет не так, удалите это, чтобы увидеть больше деталей logLevel: «тихий» }); client.init ();
Теперь мы можем описать наши тесты и использовать переменную client
для управления браузером. Полная ссылка на API webdriverjs доступна в документации , но вот короткий пример:
client.url ( 'http://example.com/') client.getTitle (функция (название) { console.log («Заголовок», заголовок); }); client.setValue ('# field', 'value'); client.submitForm (); client.end ();
Давайте использовать синтаксис Mocha и Chai для описания теста; мы протестируем некоторые свойства веб-страницы example.com
:
description ('Test example.com', function () { перед (функция (выполнено) { client.init () .url ('http://example.com', готово); }); описать («Проверить домашнюю страницу», функция () { it ('должен увидеть правильный заголовок', function (done) { client.getTitle (функция (название) { Ожидаем (название) .to.have.string («Пример домена»); сделано(); }); }); это («должен увидеть тело», функция (сделано) { client.getText ('p', function (p) { ожидать (название) .to.have.string ( «Для наглядных примеров в документах.» ); сделано(); }) }); }); после (функция (выполнено) { client.end (); сделано(); }); });
Возможно, вы захотите использовать одну client
инициализацию для нескольких тестовых файлов. Создайте небольшой модуль Node для инициализации и импортируйте его в каждый тестовый файл:
client.js
:
exports.client = require ('webdriverjs'). remote ({ // Настройки };
test.js
:
1
2
3
4
|
var client = require(‘./client’).client;
var expect = require(‘chai’).expect;
// Perform tests
|
Бег
Тестовые наборы Mocha выполняются с помощью бинарного mocha
mocha. Если вы следовали этому руководству и установили Mocha локально, то вы должны сами описать полный путь к бинарному node_modules/mocha/bin/mocha
: node_modules/mocha/bin/mocha
.
По умолчанию Mocha считает любой тест, который занимает больше двух секунд, неудачным. Учитывая, что мы фактически инициализируем веб-браузер и делаем HTTP-запрос, нам нужно увеличить это время ожидания до 5 или 10 секунд:
1
|
node_modules/mocha/bin/mocha test.js -t 10000
|
Если все шло по плану, вы должны увидеть результат примерно так:
1
2
3
|
.
✔ 1 <span class=»nb»>test complete
|
Следующие шаги
После того, как вы добились желаемых результатов функционального тестирования, вы можете подумать об улучшении настроек.
Два очевидных направления — непрерывная интеграция и распределенное тестирование Selenium.
Непрерывная интеграция
Ваша цель должна заключаться в том, чтобы минимизировать время, затрачиваемое на выполнение тестов.
Возможно, вы захотите использовать полностью автоматический сервер непрерывной интеграции, который будет запускать тесты при необходимости автоматически и сообщать вам, если что-то пойдет не так.
В мире открытого исходного кода роль такого сервера покрывает Jenkins CI : удобный, мощный и простой в установке сервис, который будет запускать тесты при необходимости, выполнять их в любой конфигурации, которую вы предоставляете, и, возможно, запускать много больше задач, связанных со сборкой, таких как развертывание кода на удаленных серверах.
В качестве альтернативы, если вы чувствуете себя авантюрным, вы можете поэкспериментировать с новым проектом под названием GitLab CI , который предлагает меньше функций, но выглядит лучше и интегрирован с GitLab , клоном GitHub, размещенным в себе.
В любом случае, ваша цель должна сводить к минимуму время, затрачиваемое на выполнение тестов. Вместо этого тесты должны запускаться автоматически и сообщать вам только о том, что что-то пошло не так.
Selenium Grid
Selenium имеет ряд ограничений по реализации. Например, вы не можете запустить несколько браузеров на одном компьютере для тестирования с помощью Selenium.
Кроме того, вы заметите, что после того, как у вас будет много тестов, их выполнение может стать длительным процессом. Хотя непрерывная интеграция частично решает эту проблему, вам все же может потребоваться запустить несколько тестов параллельно на разных компьютерах.
Наконец, вы скоро заметите, что хотите протестировать разные браузеры в разных операционных системах. И хотя ваш тестовый код теоретически может взаимодействовать с различными серверами Selenium, когда вы немного подрастете, эта настройка требует централизации.
Настройка Selenium Grid пытается обеспечить именно это. Вместо того, чтобы один сервер Selenium контролировал несколько браузеров на машине, у вас есть один сервер Selenium, который контролирует несколько узлов Selenium, каждый из которых контролирует только несколько браузеров в одной операционной системе.
Вывод
Получившийся стек, хотя и не тривиальный, на самом деле довольно прост. Добавление PhantomJS в конец Selenium позволяет нам начать использовать Selenium без особых начальных вложений, таких как настройка графических тестовых серверов.
Использование JavaScript в качестве механизма тестирования гарантирует, что наши тесты будут оставаться актуальными в контексте веб-разработки в обозримом будущем.