Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Проект Selenium WebDriver


Автор:Simon Stewart
Перевод: Н.Ромоданов

16.3. Вопросы архитектуры

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

  • Снижение расходов.
  • Имитация поведения пользователя.
  • Перекладывание всей работы на драйвера ...
  • ... и вам не потребуется разбираться с тем, как это все работает.
  • Уменьшение влияния фактора автобуса.
  • Следует дружественно относиться к реализации языка Javascript.
  • Вызов каждого метода является дистанционным вызовом RPC.
  • Это проект с открытым исходным кодом.

16.3.1. Снижение расходов

Поддержка для X браузеров на Y платформах изначально дорогостоящее занятие, как с точки зрения первоначальной разработки, так и сточки зрения сопровождения. Если мы сможем найти какой-нибудь способ сохранять высокое качество продукта, не нарушив при этом слишком много других принципов, то это именно то, что нам могло бы подойти. Наиболее ярко это видно по нашему выбору везде, где это возможно, использовать язык Javascript, о чем вы скоро прочитаете.

16.3.2. Эмуляция поведения пользователя

WebDriver предназначен для точной имитации того, как пользователь будет взаимодействовать с веб-приложением. Обычным подходом в имитации пользовательского ввода является применение языка Javascript для создания ряда событий, которые приложение будет воспринимать, как если бы реальный пользователь выполнял те же самые действия. Этот подход с использованием «синтезированные событий» чреват трудностями, поскольку каждый браузер, а иногда и разные версии одного и того же браузера, ведут себя немного по-разному. Ситуация усложняется тем, что в большинстве браузеров пользователю по соображениям безопасности не разрешено использовать такие элементы форм, как ввод файлов.

Везде, где это возможно, WebDriver использует альтернативный подход запуска событий на уровне операционной системы. Поскольку такие «нативные события» нельзя генерировать браузером, такой подход позволяет обойти ограничения безопасности, накладываемые на генерируемые события, а поскольку они характерны для конкретной ОС, то раз уж они используются для одного браузера на конкретной платформе, то их сравнительно легко использовать и для другого браузера. К сожалению, такой подход является единственно возможным, когда WebDriver может тесно взаимодействовать с браузером и когда команда разработчиков определяет, как лучше посылать нативные события и, при этом, не передавать фокус окну браузеру (тесты Selenium выполняются в течение долгого времени и, пока они работают, было бы хорошо иметь возможность использовать машину для выполнения других задач). На момент написания данной главы это означало, что нативные события можно было использовать в Linux и в Windows, но не в Mac OS X.

Независимо от того, каким образом WebDriver эмулирует пользовательский ввод, мы стараемся настолько точно имитировать поведение пользователя, насколько это возможно. Это контрастирует с использованием RC, в котором содержится API, действующее на гораздо более низком уровне, чем работает пользователь.

16.3.3. Перекладывание всей работы на драйвера

Может быть, это прозвучит банально, как, например, то, что вода должна быть мокрой, но я считаю, что нет смысла писать код, если он не работает. То, что драйверы работают в проекте Selenium мы доказываем тем, что у нас есть достаточно много наборов автоматизированных тестов. Они, как правило, являются «интеграционными тестами», требующими компиляции кода и используемыми при взаимодействии браузера с веб-сервером, но там, где это возможно, мы пишем «юнит-тесты», которые, в отличие от интеграционных тестов, могут работать без полной перекомпиляции. На момент написания главы было приблизительно 500 интеграционных тестов и приблизительно 250 юнит-тестов, которые можно было выполнять с каждым браузером. Сейчас их больше, поскольку мы выпускаем новые версии и пишем новый код и наш интерес смещается в сторону написания юнит-тестов.

Не каждый тест работает с каждым браузером. Некоторые проверяют специфические возможности, которые не поддерживаются в некоторых браузерах или которые в разных браузерах обрабатываются по-разному. Примерами могут служить тесты для новых возможностей HTML5, которые поддерживаются не всеми браузерами. Несмотря на это, для каждого из основных браузеров, работающих на настольных машинах, есть достаточно важно подмножество тестов, работающих именно с ним. Понятно, что найти способ, как для каждого браузера на нескольких платформах запустить более 500 тестов, является серьезной задачей и это одна из тех задач, с решением которых продолжает бороться проект.

16.3.4. Вам не нужно понимать, как это все работает

Очень немногие разработчики достаточно опытные, что им комфортно работать с всеми языками и технологиями, которыми мы пользуемся. Поэтому наша архитектура должна позволить разработчикам сосредоточить свои таланты на том, где они могут принести наибольшую пользу, и не требовать от них работать с теми частями кода, с которыми им работать некомфортно.

16.3.5. Уменьшение влияния фактора автобуса

Есть (не очень серьезная) концепция разработки программ, называемая «фактор автобуса». Она касается ряда ключевых разработчиков, с которыми может произойти нечто ужасными – предположим, их собьет автобус – в результате проект может быть оставлен в том состоянии, в котором его не удастся продолжить. Некоторые такие сложные проекты, как автоматизация браузеров, особенно подвержены влиянию этого фактора, поэтому в многих наших архитектурных решениях этот фактор учитывается как можно ответственнее.

16.3.6. Следует дружественно относиться к реализации языка Javascript

WebDriver в случае, если нет другого способа управлять браузером, возвращается обратно к управлению с помощью чистого языка Javascript. Это означает, что любой интерфейс API, который мы добавляем, должен быть дружественным к реализации языка Javascript. Что касается конкретного примера, то в HTML5 добавлено локальное хранилище LocalStorage — интерфейс API для хранения структурированных данных на клиентской стороне. Это обычно реализовано в браузере с использованием пакета SQLite. Естественной реализацией было бы реализовать подключение к базе данных с помощью находящегося ниже механизма хранения данных, использующего что-нибудь вроде JDBC. В конце концов, мы остановились на интерфейсе API, который достаточно точно моделирует лежащую ниже реализацию Javascript, т. к. все, что моделирует обычные интерфейсы API, используемые для доступа к базам данных, не не слишком дружественно к реализациям языка Javascript.

16.3.7. Каждый вызов — это дистанционный вызов RPC

WebDriver осуществляет управление браузерами, которые работают в других процессах. Хотя проще это не учитывать, но это означает, что каждый вызов, который сделан через интерфейс API фреймворка, является дистанционным вызов и, следовательно, производительность фрейворка всецело зависит от задержек в сети. Т.к. в большинстве ОС для localhost маршрутизация оптимизирована, то в обычном режиме работы, это, быть может, не очень заметно, но как только сетевые задержки между браузером и кодом теста становятся больше, для разработчиков интерфейса API и его пользователей начинает казаться, что эффективность уменьшается.

Это оказывает определенное влияние на разработку API. В большом API с грубо сделанными функциями можно было бы сократить задержку за счет отказа от использования множественных вызовов, но при этом следует соблюсти баланс между выразительными возможностями и простотой использования API. Например, есть несколько проверок, которые нужно сделать для того, чтобы определить, является ли элемент видимым для конечного пользователя. Мы должны принять во внимание не только различные настройки CSS, что, подразумевается, может потребовать просмотра родительских элементов, но нам, вероятно, также следует проверить размеры элемента. В минималистском варианте интерфейса API необходимо, чтобы каждая из этих проверок делалась отдельно. В WebDriver они объединены в одном методе isDisplayed.

16.3.8. Заключительный штрих: Это проект с открытым исходным кодом

Хотя это не совсем архитектурный аспект, но Selenium является проектом с открытым исходным кодом. Основная мысль, которая объединяет все вышеуказанные аспекты вместе, в том, что мы хотели сделать так, чтобы каждому новому разработчику было бы проще вносить в проект свой собственный вклад. Мы надеемся добиться этого за счет того, что поддерживаем минимальные требования к уровню знаний, необходимых новым разработчикам, используем минимально необходимое количество языков и для того, чтобы проверить, что ничего не испорчено, используем автоматизированные тесты.

Первоначально проект был поделен на ряд модулей, причем каждый модуль, представляющий конкретный браузер, имел дополнительные модули, реализующий обычный код, и модули с кодами поддержки и утилит. В этих модулях также хранились деревья исходных кодов для привязок к конкретным языкам. Этот подход был достаточно осмысленным для таких языков, как Java и C#, но создавал проблемы для программистов, работающих с языками Ruby и Python. Это почти сразу привело к тому, что интерес к проекту проявило только очень немного пользователей, способных и заинтересованных использовать привязки к языкам Python и Ruby. Чтобы решить эту проблему, в октябре и ноябре 2010 года исходный код был реорганизован так, что для языков Ruby и Python код хранился в папках верхнего уровня отдельных для каждого языка. Это больше соответствовало ожиданиям разработчиков открытого исходного кода, использующих эти языки, и практически сразу это дало эффект в повышении вклада, делаемого сообществом разработчиком.

Продолжение статьи - Побеждаем сложность.