Готовые решения для QA: как писать автотесты на Groovy

Статья подготовлена на основе доклада Ярослава Святкина на конференции QA Fest. Ярослав — тренер QA Automation & Groovy, Senior Test Automation Engineer, Consultant, GlobalLogic. Специализации: автоматизация web и mobile (Android и iOS), пишет на Java и Groovy.

В этой статье я поделюсь, как быстро писать тесты на языке программирования Groovy, не думать о фреймворке, PageObject и инициализации WebDriver. Фреймворк это сложно? Нет! Я покажу способ, который позволяет думать о тестировании приложения, а не о структуре кода. Я расскажу о трех фреймворках — Serenity, Selenide и Geb.

«Все, теперь начинаем автоматизацию!»

Первое, с чего стоит начать автоматизацию, — подумать, что нужно сделать, чтобы ничего не писать, а если и писать, то как можно меньше. Чем меньше вы пишете, тем меньше ошибок вы делаете. К тому же у вас появляется свободное время, чтобы выпить кофе, пообщаться с друзьями или заняться самообразованием.

Второе — не тратить время на изобретение велосипеда для создания тестового фреймворка. Что обычно делает большинство? Мы открываем библиотеку Selenium, пишем уровни фреймворка — страницы, тесты, бизнес-логику и т. д. После этого всего еще обязательно тратим драгоценное время на создание отчета, который не стыдно было бы показать клиенту.

Велосипед, или Что мы все обычно делаем

Первое, что мы ищем, — как описывать страницы, что могло бы в этом нам помочь. В описании модели PageObject целесообразно использовать элемент Html Elements.PageObject. Кто-то его использует, кто-то — нет, но он дает возможность описать определенные элементы и использовать их повторно.

@Name("Search form")
@FindBy(xpath = "//form")
public class SearchArrow extends HtmlElement {

    @Name("Search request input")
    @FindBy(id = "searchInput")
    private TextInput requestInput;

    @Name("Search button")
    @FindBy(className = "b-form-button__input")
    private Button searchButton;

    public void search(String request) {
        requestInput.sendKeys(request);
        searchButton.click();
    }
}

Еще одно полезное средство — дополнительный фреймворк JDI UI Test Automation Framework. Он помогает в основном создавать объекты: check boxes, text areas и т. д. с дополнительным мета-тегами и всем необходимым. Этот фреймворк помогает описать PageObject.

@JSite(domain = "https://jdi.com")
public class JDIExampleSite extends WebSite {
    public static HomePage homePage;

    public static LoginForm loginForm;

    @FindBy(css = ".profile-photo")
    public static Label profilePhoto;

    public static void login() {
        profilePhoto.click();
        loginForm.loginAs(new User());
    }
}

Для уровня описания страниц он подходит, но всегда хочется большего — все максимально автоматизировать. В отличие от библиотек, которые помогают работать для описания модели в рамках PageObject, существуют тестовые фреймворки с уже готовыми решениями. Гибкость, конечно, теряется, в этом и отличие готового решения от самописного. Собственный «велосипед» всегда более гибкий.

Вот три готовых решения вам в помощь.

Стандартное решение — Serenity

Если вы хотите использовать тестовый фреймворк, вы можете воспользоваться определенным комплексом готовых решений. Один из них — Serenity. Это целесообразно, если у вас есть не очень опытная команда, а вам нужно построить процесс автоматизации с нуля.

С данным решением автоматизацию возможно построить и с одним сеньором в команде так как это решение из коробки. У вас будет от начала и до конца продуманная архитектура, поддержка Jira, хороший отчет и многое другое.

Project structure

Итак, у нас есть уровень PageObject для описания страниц, есть шаги и тест — это классический подход к построению тестового фреймворка. Мы отдельно распределяем уровень страниц (описание нашего приложения), отдельно выносим бизнес-логику. При использовании бизнес-логики пишем тесты, чтобы они не обращались к страницам напрямую.

PageObject мы используем в следующем виде:

Я думаю, все видели FindBy и знают, как он пишется (селекторы и т. д.). А вот как выглядят шаги, описание бизнес-логики:

Что немаловажно — красиво оформленный, готовый к распечатке отчет:

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

Оптимальное решение — Selenide

Тестовый фреймворк Selenide в последнее время стали активно использовать. На него иногда даже соглашаются и заказчики, хотя многие из них все же требуют исключительно Java 7 и Selenium. Это происходит из-за того, что созданные автотесты нужно поддерживать, а те, кто будет их поддерживать, о новых фреймворках могут не знать.

Самый большой плюс — мы можем поставить знак $ (любимый знак с точки зрения айтишников) и дальше написать все, что хотим. Реализация вейтов уже существует:

Готовое решение — Geb

Geb — готовое решение, которое можно смело использовать при написании вашего фреймворка. На сайте gebish.org доступна очень хорошая документация, которая постоянно обновляется актуальными дополнениями. Geb очень информативен. Вы можете сравнивать все, не надо подключать сторонние библиотеки, как это делается в JUnit и Hamcrest.

Первое преимущество Geb — использование языка Groovy. C одной стороны, это плюс. Во-первых, чтобы писать на Groovy, надо писать очень мало. Во-вторых, он использует Java, поэтому все Java-библиотеки, которые у нас есть, мы можем «переиспользовать». Дополнительно — в нем замечательные asserts, которые не надо расписывать, как в TestNG или JUnit. Большой минус в том, что, во-первых, чтобы команда начинала писать на Groovy, вам надо сначала обучить команду. Во-вторых, не всегда заказчик готов к использованию Groovy, чаще к Java, а лучше Java 7.

Аналогично Selenide, в Geb можно использовать знак $. Здесь у нас есть уже готовые методы waitFor. Если раньше нам приходилось их описывать, то в Geb мы просто передаем заготовки, чтобы сообщить, сколько надо ждать. Есть и waitFor по умолчанию, позволяющее ждать до определенного момента. В следующем примере описана ситуация, когда необходимо подождать, пока не будет отображен определенный элемент:

import geb.Browser

Browser.drive {
    go "http://gebish.org"

    assert title == "Geb - Very Groovy Browser Automation" 
 $("div.menu a.manuals").click() 
    waitFor { !$("#manuals-menu").hasClass("animating") } 
  $("#manuals-menu a")[0].click() 
assert title.startsWith("The Book Of Geb") 
}

Тяжело ли писать такой код? По-моему, очень легко. Естественно, у нас есть first-метод, с помощью которого можно выбрать все элементы со знаком $. В данном случае нам нужен первый, поэтому мы указываем единицу — «первый элемент» и «клик». Это классический вариант.

При использовании Groovy у вас появляется широкий спектр возможностей. Приведу несколько примеров. Например — создание random string для необходимого количества значений возможно в одну строку:

Следующее — когда перед вами стоит задача протестировать API и у вас есть HTTP-запрос, вы получаете JSON-файл, который нужно «распарсить» и получить определенный результат. В Java вам нужны сторонние библиотеки для работы с JSON-файлом. В Groovy же поддержка парсинга и разбора JSON-файла происходит «из коробочки».

В итоге я стал писать совсем по-другому. Я получал JSON и привожу к ArrayList, и на выходе у меня получался ArrayList.

В Groovy любой массив может быть объектом. Вы берете определенный массив и пишете: (massive as Duckling). Если все характеристики совпадают, у вас появляется объект Duckling. Кроме того, у вас есть возможности точно так же описывать JSON:

Выбор селекторов

Выбор селекторов огромен — и это самая большая проблема в их выборе. Кто-то любит CSS, а кто-то XPath. Я отношусь к последним и мог бы привести множество аргументов в пользу XPath.

Здесь можно использовать ID и клас By. Любимый класс By позволяет нам по тому или иному селектору сделать выбор тех или иных элементов.

Обратите внимание на assert в этом изображении. Здесь есть знак $. Выбираем все символы p в диапазоне с первого по второй. С помощью метода *.text выбираем весь текст этих элементов (значок * свидетельствует о том, что используется метод языка Groovy), и нам возвращается полный текст со всех элементов.

Сколько обычно необходимо действий, чтобы выбрать определенный набор элементов: «все ячейки» или «все строки таблицы» — из таблицы с каждого элемента пробежаться и выбрать весь текст? Вам надо писать цикл, выбирать все элементы, на каждом выбирать метод *.text и, соответственно, куда-то складывать результаты. Метод *.text возвращает полностью список ваших текстов на всех элементах.

В XPath иногда нам не хватает возможности использовать матчеры и, соответственно, регулярные выражения. Здесь это можно использовать прямо «из коробки». Это очень большой бонус и очень большой плюс для процесса автоматизации тестирования. Естественно, по тексту не очень хорошо выбирать, но по классу вы можете это сделать.

Кроме этого, есть методы, с которыми можно работать почти как со строками:

Также еще есть и масса других методов:

Один из вариантов, где показано, что нам доступно, в рамках Geb и Groovy в целом, использовать XPath с передачей аргумента:

Если сравнивать написание кода с помощью Geb и классический подход, то 25 строчек кода на Java заменит одна строчка на Groovy c Geb.

Что еще может вам помочь в работе над проектами? У нас есть понятие методов wait, и не всегда на странице есть те или иные элементы. Для проверки мы пишем метод isElementPresent, делаем track catches, обрабатываем, возвращаем true или false.

И снова в Geb все это есть в готовом виде. Первое, у нас есть wait, который определяет, ждать элемент на странице или нет. Мы можем не ждать появления этого элемента, а проверить его наличие.

Существует wait, который определяет, сколько секунд ждать при поиске элементов. Вы сразу задаете его в селекторе при описании PageObject. Элемент может также принимать параметр required true (или false), т. е. определяет, должен или нет этот элемент находиться на этой странице.

Для кэширования в Geb тоже есть вариант. Вы можете прямо в селекторах указать:

  • страницу перехода;
  • действия, которые необходимо произвести;
  • элемент страницы, который необходимо вернуть для дальнейшего использования.

Работа с таблицами

Кроме того, что в Geb есть готовые элементы, также есть и возможность использования двух основных классов для построения PageObject-модели: страница и настраиваемый модуль.

Раньше у вас была таблица, где нужно было выбирать все элементы, выстраивать в определенные объекты и с ними дальше работать. Тут же этого делать не нужно — каждая строка является определенным модулем со своим набором значений. В рамках этого модуля вы всегда можете вернуть набор модулей из таблицы и с ним вызывать необходимые вам методы.

В рамках фреймворка можно использовать и описывать определенные элементы, которые будут использоваться в разных страницах с помощью класса Module. Этот модуль может содержать в себе еще модули. Благодаря этому может выстроиться полная иерархия приложения. Вы сможете переиспользовать эти модули в любой странице, не описывая код несколько раз на страницах.

Как это делается? Давайте посмотрим:

В описании PageObject в Geb есть NotificationModule, а также элементы:

  • имя элемента;
  • через фигурные скобки — селектор этого элемента;
  • moduleList в рамках модуля, где мы вызываем еще один модуль.

Ссылка на элемент является ссылкой на набор объектов другого модуля. Это все пишется в одну строчку. Notification у нас является дополнительным модулем с именем и датой. Заметьте, на модуле сразу вызывается метод, который вызывает этот элемент.

В конце концов, я перестал писать методы на элементах. Если я обращаюсь к определенному элементу, мне сразу возвращается или текст, или я по нему кликаю, или выполняю другие действия прямо в рамках PageObject.

Теперь о результатах. Благодаря searchResult будут полностью возвращаться все найденные тексты для выбранных элементов. Если теперь вы будете использовать link, у вас получится следующее:

Если вам нужно вызвать все методы — ставите «звездочку» и точку (*.), и вам возвращается все, что вы хотите (это Groovy).

При классическом подходе нам необходимо проверить, на той ли странице мы находимся. Т.е. после перехода на страницу проверить ее релевантность, далее действовать в зависимости от результата. Об этом разработчики Geb также позаботились и предложили готовый вариант:

Когда вы пишете PageObject, у вас используется метод static at. Вы просто указываете, какой элемент на странице должен присутствовать в текущем состоянии, если вы находитесь на конкретной странице.

Если вам необходимо проверить, находитесь ли вы на странице, у вас есть замечательный метод isAt. Вы передаете текущую страницу, и у вас получается проверка true/false (на текущей странице или нет). Опять же в Geb это все идет «из коробочки».

Вот классический пример такой страницы (с логином и паролем):

Если вы хотите произвести метод логирования, у вас классически передаются логин/пароль, возвращаются элементы, вы их очищаете и с помощью Groovy вводите значение. Метод login.submit находит и вызывает кнопку, по которой вы сразу же кликаете.

Для описания этих действий на Java 7 с использованием Selenium придется создавать гораздо больший объем кода, чем приведенный выше. С точки зрения приложения, использование Geb очень упрощает описание PageObject.

Взаимодействие с мышью и поддержка кнопок

В Selenium у нас есть набор Actions — действий, которые мы можем использовать:

  • наведение мыши;
  • работа с веб элементами;
  • drag-and-drop и так далее.

Для этого нужно создать объект Action, выполнить определенные действия для него и произвести эти действия. В Geb вы можете произвести те же действия — .clickAndHold, .moveByOffset и любые другие. Разработчики фреймворка Geb предусмотрели все «под ключ». Остается единственный вопрос: почему мы это не используем?

Здесь есть и поддержание кнопок:

Иногда мы испытываем большие трудности — как ввести те или иные значения или поля. Когда появляются Windows-окна, мы используем кто во что горазд. В Geb есть возможность использовать любые кнопки, вкладки, переходы.

Ранее открытые окна и тесты

Еще одна проблема — переход между окнами при открытии ссылок. Мы переходим на следующее окно, выполняем в нем определенные действия, проверяем, что они завершены, после чего возвращаемся в предыдущее окно. В Google можно найти огромное количество решений и скопировать необходимый фрагмент кода. На этот сложный алгоритм есть готовое решение в Geb:

Для этого в Geb предусмотрены методы withWindow и withNewWindow. Чем они отличаются? Метод withWindow — новое окно открывается в существующем, производятся действия проверки и сразу же возвращается в предыдущее окно.

withNewWindow открывает новое окно, что намного упрощает процедуру. Для этого вы указываете, какое действие надо произвести, чтобы перейти на другое окно — кликаем и проверяем, что мы находимся на текущей странице (в рамках нового окна). Когда действие заканчивается, автоматически мы возвращаемся обратно в предыдущее окно. Никаких дополнительных действий не нужно.

Сколько строк кода вам нужно написать или скопировать, чтобы это реализовать? В Geb весь тест будет записан в одну строчку, ничего сложного:

Открываем меню, открываем браузер, переходим в новое окно, кликаем assert, проверяем startsWith. Второй вариант теста аналогичен первому, но только предусматривает открытие нового окна.

Показ скрытого элемента

Довольно часто мы используем в коде JS, так как есть вещи, которые без него сделать нельзя. Например, реализовать scroll. Для этого нужно написать определенный кусок кода, привести его к Java executor и прочее.

И снова в Geb есть все, что нам необходимо. Если вы хотите использовать JS-код, вам надо всего лишь написать js.exec и указать, что именно вы хотите выполнить:

Кроме того, что в Geb есть встроенная поддержка JS, поддержка jQuery. Это может значительно расширить возможности с точки зрения фреймворка и оптимального описания необходимых действий.

Поддерживаемые браузеры

В Geb поддерживаются все браузеры, которые есть в рамках WebDriver. Обычно в наших решениях мы делаем driver factory, отдельно описываем необходимые браузеры, далее его «подтягиваем» и запускаем — с учетом специфики job. В фреймворке Geb это вынесено по умолчанию. Здесь уже есть отдельный файл — GebConfig.groovy, который мы должны создать по умолчанию и в нем описать браузеры, а также тестовую среду:

Сюда можно полностью вынести все необходимые для тестов константы (имя, пароль, e-mail), настройки тестов, правила проверки, тайм-аут по умолчанию и прочее. Далее — область тестовой среды (test environment), для которой мы задаем имена окружения (Chrome, Firefox, IE) и создаем те драйвера, которые необходимы.

Понятно, что в рамках используемого build (Gradle или Maven) создаются определенные tasks. При этом для Gradle build необходимо прописать свойства системы (System Properties), а именно с каким environment будут запускаться тесты, где лежат драйвера той или иной тестовой среды:

В данном случае мы используем фреймворк TestNG и видим пример запуска тестового набора (test suite). В зависимости от того, какие tasks вы создали, у вас будет запускаться та или иная тестовая среда в рамках существующего.

Если вы настраиваете Jenkins, вы запускаете job и тестовые наборы стартуют в определенной тестовой среде. Все это работает легко и понятно. Даже новичок в команде может очень быстро и легко разобраться, как стартует ваш проект, на какой тестовой среде, где находятся настройки и как это все запускать.

Интеграции с mobile

Geb и Spock — это одна связка, новые подходы в BDD. Лично у меня не очень получилось использовать Geb+Spock, и вот почему. Когда я предлагал команде использовать Geb — все соглашались, но когда я предложил использовать еще и Spock, это посчитали слишком сложным решением, так как необходимо переходить полностью на новый стек технологий.

Но очень хорошо у меня получилось использовать Geb с Cucumber. У него очень хорошая поддержка, BDD, хорошо оформленный отчет. Внутри, конечно же, была поддержка Geb и все страницы описывались с помощью Geb. Поддерживаются также JUnit и TestNG, и все тестовые проверки на базе этих фреймворков можно делать в Geb.

Библиотека Geb Mobile помогает создавать и использовать Geb для нативного Android- или iOS-приложения. Конечно, кое-что не будет работать в связи со спецификой нативных мобильных приложений, но построение PageObject, модулей можно применять и к этим приложениям.

Преимущества и недостатки готового решения

В заключение перечислим преимущества и недостатки использования Geb.

Преимущества:

  • Использование языка Groovy (краткость).
  • Готовая PageObject-модель, которую вы можете использовать для написания методов wait, переходов между страницами и пр.
  • Поддержка всех тестовых фреймворков, сочетание с Cucumber, jUnit, TestNG.

Недостатки:

  • Мало кто знает Groovy.
  • Необходимо уговорить заказчика начать использовать новые фреймворки и технологии. Для заказчика главный вопрос — кто это будет поддерживать.

У каждого решения есть свои достоинства и свои недостатки. При выборе технологического стека определяться вам! Этот выбор зависит от состава и знаний вашей команды и задач, которые вы хотите решить.

Похожие статьи:
Представляем вам новости из мира Ruby/Rails в нашем дайджесте за июнь! Ознакомьтесь с последними обновлениями и функционалом Ruby/Rails,...
Описание: JavaScript — универсальный скриптовый язык, весьма гибкий и мощный. JavaScript находит широкое применение как язык описания...
Меня зовут Александр Черненко, и я 5 лет занимаюсь Front-end-разработкой. Я Technical Lead в компании Nullgravity, и мне удалось вырастить...
Приходите на Java.io 3.0 — встречу для всех, кого интересует Java и всё, что так или иначе с ней связано! Третья встреча Java.io...
Когда продукт — это сеть взаимосвязанных сервисов с большим количеством внешних зависимостей, то ответ на простой...
Яндекс.Метрика