Pull to refresh

Как Clojure помогает ускорить написание Selenium-тестов

Reading time 7 min
Views 14K

image Привет, читатель! Если доводилось писать Selenuim-тесты чуть сложнее чем на пару полей ввода и одну кнопку, то эта статья может пригодиться.


Наверняка знакомо чувство неправильности происходящего, когда внезапно отказывался работать тест-кейс длиной в пару минут, вынуждая тыкаться вслепую, чтобы найти поломавшийся css- или xpath-селектор в сложном Single Page Application, раз за разом запуская этот медленный сценарий, только чтобы дождаться вывода лога в консоль. Оказывается, можно писать Selenium-тесты с комфортом!


О чём статья - другими словами для нубов

Про Selenium. Когда-то это был просто плагин для FireFox. Нажимаешь кнопочку "запись", и начинаешь дергать интерфейсы тестируемого сайта (формочки, ссылки). Практически без знания программирования, полученный сценарий можно править, подставляя нужные значения проверок. Всё — тест готов! Запускай каждый раз после деплоя, и проверяй, чего сдвинул локтем. Потом в Selenium добавили API для разных языков. В частности есть и для JAVA. Через API можно делать тоже самое: запускать браузер с требуемым сайтом, проверять переданные значения в формах, ходить по ссылкам и т.д. Беда в том, что скрипт выполняется медленно. Чтобы тестировать тесты, надо перезапускать сценарий, а это форменная пытка. Clojure (поверх JAVA) позволяет выполнять куски кода в работающей программе посредством REPL прямо в редакторе!


Разбор проекта с Selenium-тестами


Проект доступен на GitHub, особенности:


  • Кроссплатформенность — писать тесты можно под ОС Windows, с профайлом +windows, затем собирать jar файл под *nix, и выкладывать на сервер.
  • Работа сразу с двумя web drivers: selenium и phantom, это удобно когда нужно визуально отладить тест в Selenium, скомпилировать jar, который работает с Phantom и залить его на Linux-сервер где его будет дергать какой-нибудь CI-скрипт.

В зависимостях проекта можно увидеть библиотеку — clj-webdriver, это основной инструмент для работы с веб-драйвером, документация к нему.


Разберем простой тест example-selenium-project.tests.gosuslugi-main:


(deftest gosuslugi-main-search-form
  (profile/open-browser "https://www.gosuslugi.ru/")
  (try
    (->> ($ ".index-slider-search input")
         (type-text "загранпаспорт")
         (->>keys Keys/ARROW_DOWN)
         (->>keys Keys/ARROW_DOWN)
         (->>keys Keys/ENTER))

    (when-not ($ ".title_search")
      (throw (Exception. "redirect to search result, error")))

    (swap! profile/tests-success inc)
    (is true)
    (log/info "gosuslugi-main-search-form -> ok")

    (catch Exception e
      (log/info "gosuslugi-main-search-form -> fail" (.getMessage e))
      (swap! profile/tests-fail inc)
      (is false))))

(deftest gosuslugi-main-search-form ...)

deftest — макрос, импортируется из библиотеки clojure.test. Это встроенная в Clojure библиотека для написания тестов. Имеет стандартный для тестов функционал. Макрос deftest просто создает функцию.


Сам тест обернут в (try ... catch) для удобства, чтобы прерывать выполнение формы вызовом Exception, или же в любых нестандартных случаях (например, если не найден элемент), и выполнять форму в catch, обрабатывающую провал теста.


(->> ($ ".index-slider-search input") ...)

->> — стандартный Clojure-макрос для написания более читабельного кода "шиворот навыворот". Без него сценарий выглядел бы так:


(->>keys Keys/ENTER
 (->>keys Keys/ARROW_DOWN
  (->>keys Keys/ARROW_DOWN 
   (type-text "загранпаспорт" ($ ".index-slider-search input")))))

Макрос ->> принимает список форм и раскрывает их, передавая последовательно результат выполнения, как последний аргумент, следующей форме. Чтобы использовать макрос ->>, я сделал несколько функций-обёрток, которые следуют простому соглашению — принимают последним аргументом объект element, и возвращают его же.


(swap! profile/tests-success inc) и (swap! profile/tests-fail inc) — простые счетчики успешных и проваленных тестов.


Почему Clojure?


Простой ответ — уровень абстракции над сложностью. Должно быть ты уже сходил в Википедию, посмотрел на синтаксис этого Lisp-диалекта, и проходишь первую стадию принятия неизбежного. Пройдёшь её или нет — дело твоё, могу только дать несколько советов, основанных на опыте.


  • Clojure — легкий в изучении язык, более высокий порог входа связан с его отличием от императивного подхода, который нам вбивают в голову со школы. Переборов закостенелость сознания, мы увидим что Clojure превращается в удобный инструмент, позволяющий упростить разработку приложения.
  • Как же не запутаться в таком обилии скобок? Особых проблем со скобками нет, к ним привыкаешь за день, когда понимаешь их назначение. Так же в редакторах появился ряд хороших инструментов, которые облегчают инкубационный период Clojure-разработчика. Во-первых, прекрасный Parinfer, доступен для большинства редакторов. А во-вторых, банальное включение в настройках редактора радужных скобок.
  • Для написания тестов не понадобится доскональное знание Clojure. Трансдьюсеры, редьюсеры и прочая муть — изучение этого можно отложить на потом. Для старта достаточно освоить базу за пару-тройку вечеров.

Как Parinfer помогает закрывать скобки в зависимости от отступов

Быстрый старт по инструментам разработки


Если бы ты провел молодость будучи хиппи в Америке 60-х годов, то мог вкусить дух свободны, демократии и лёгких наркотиков; если не довелось, ничего страшного — этот дух ты можешь ощутить используя в работе REPL Clojure.

REPL Clojure — выводит написание Selenium-тестов на совершенно иной уровень! Ключевая особенность этого REPL от любых других в том, что можно писать код в уже работающем приложении, не теряя его состояний. Этот инструмент позволяет не просто составлять рабочие css- или xpath-селекторы, но и проводить тесты в каком угодно порядке, и проверять работоспособность любого из узлов большого тест-кейса не теряя состояния сложного Single Page Application.


Демонстрация возможностей REPL в редакторе Atom


Выполнение кода нашего проекта построчно посредством REPL в редакторе LightTable


Редактор кода для Clojure — почти под все популярные редакторы и IDE существуют плагины для поддержки Clojure, я остановился на IntelliJ IDEA + Cursive, как имеющий наименее низкий порог входа. Небольшая инструкция по настройке и использованию REPL в Cursive.


Также популярны:



Leiningen — менеджер зависимостей, как npm из мира Node.js. С тем отличием, что, как зависимость, Leiningen преподносит ещё и сам интерпретатор Clojure. Поэтому нам достаточно будет установить Leiningen, Clojure он скачает сам.


Про библиотеки

Основной репозиторий Clojure, так же можно использовать библиотеки из maven-репозитория (несметные богатства Java-сообщества). Подборка полезных библиотек.


После этого можно создать новый Clojure-проект, набрав в консоли:


lein new app example-selenium-project

Leiningen создаст нам всё дерево проекта и конфигурационный файл — project.clj, (в npm его аналог — package.json).


Таже в Leiningen очень хорошо реализована работа с профайлами, определив ряд своих профайлов в разделе :profiles файла project.clj, можно очень гибко разделять работу программы в окружениях develop или production, и не только.


Можно запускать приложение с любым количеством профайлов, например:


lein with-profile +windows,+selenium run

Или скомпилировать jar с нужными профайлами:


lein with-profile +windows,+phantom uberjar

Заключение


Рискну предположить что Clojure является на сегодня наиболее удобным инструментом для написания Selenium-тестов. Благодаря двум факторам: интерактивному REPL и макросам, которые позволяют создать свой собственный лаконичный DSL-подпроект. Как показывает практика, можно не знать сам язык Clojure и успешно работать с DSL на фасаде. Это открывает неплохие возможности к быстрому подключению новых специалистов к написанию и поддержке тестов.


Полезные ссылки



Критика статьи в Slack-чатике #clojure-russia

yashaka
у меня есть подозрения что за трай кетч в тест логике могут не слабо накинуться… любые сложные конструкции типа ифов, циклов, трай кетчов — считаются плохим тоном в написании тестов


в нашем примере — это ведь функционал логирования по сути, и такие вещи обычно выносят в какие то абстракции…


может если есть желание показать удобство, то стоит показать как вынести такой код логирования в какую то — то ли функцию толи макрос дополнительный вокруг deftest


seryh
ну юнит тесты и селениум тесты, разные вещи. на практике try в селениуме очень удобен. так как почти все отваливания тестов происходят из за устаревших селекторов (edited) или еще какой внезапной фигни которую сложно предсказать


yashaka
логика “не использовать сложные конструкции” растет от того факта что тестов много, они могут менятся, и их пишет большое количество людей — поэтому нет времени сильно вдумываться в флоу — тесты должны быть буквально очевидными


по крайней мене насколько я это себе понимаю:)


в селениум тестах — это еще более важно, так как тесты сложнее сами по себе…


seryh
да простор для улучшения большой ) руки пока не дошли


yashaka


или еще какой внезапной фигни которую сложно предсказать

внезапная фигня — это в любом случае эксепшен
и полетевший эксепшен — это уже упавший тест с репортом


просто встроенные в селениум эксепшены — мало информативны


поэтому люди и пишут свои врапперы вокруг селениума


как бы потому — что бы тест логика оставалась простой и очевидной…


seryh
я там в статье отметил в заключении что можно dsl написать простой


а в примере, так наколенная поделка


yashaka
я сам автоматизатор, а не разработчик, и вишу тут в чатах на эту тему,
и там как только какой то новичок показывает тест с ифами и трай кетчами — сразу льются горы нравоучений…
здесь суть не в том что хорошо а что плохо…
а в том что и так у нас посыл громкий как для неформального языка, и народ начнет лить критику :)
и получается мы им с нашими “наколенными подделками” только еще больше повода даем


У меня сейчас завал, поэтому к сожалению нет времени на то что бы помочь… Но если мы не спешим, то где то через недельку-вторую, я смог бы поконтрибьютить в эту статью…


motor4ik
а кейс самый главный не рассмотрен в статье? что упал тест и как его реплом починить?


я так понимаю это была киллерфича статьи нет?


seryh
публикация на понедельник запланирована. вообще если взлетит то можно и вторую статью запилить


и свой dsl для тестирования запилить =Р


а так, небольшой примерчик сейчас, вполне понятный новичку


P.S. Я выступаю лишь в роли вдохновителя и редактора, автор статьи — seryh.

Tags:
Hubs:
+19
Comments 12
Comments Comments 12

Articles