Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

Автоматизация тестирования Prom.UA на примере Java и JBehave

bdd
junit
hamcrest
jbehave
spring
java
Теги: #<Tag:0x00007f7b621693f8> #<Tag:0x00007f7b621692b8> #<Tag:0x00007f7b62169178> #<Tag:0x00007f7b62169038> #<Tag:0x00007f7b62168ef8> #<Tag:0x00007f7b62168db8>

(Irinkav) #1

Оригинал статьи размещен на сайте Сообщество программистов | DOU по ссылке: Автоматизация тестирования Prom.UA на примере Java и JBehave

Оставляйте, пожалуйста, свои комментарии к статье на DOU по ссылке выше.

Спасибо.


Исходный код приложения доступен здесь. Загрузить его себе можно с помощью команды:

git clone https://github.com/irinkav/promua-test-app.git

Содержание

Вступление

Некоторое время назад у меня появилось желание попробовать на Java написать простенькое приложение для тестирования веб-интерфейса Prom.UA, которое бы следовало популярному сегодня направлению разработки приложений — BDD (Behavior-Driven Development). И в этой статье я хочу поделиться своей находкой в этом направлении.

Начну с того, что свое внимание я остановила на BDD потому, что, как мне кажется, этот процесс, расширяя идеи TDD (Test-driven development), фокусирует наше внимание на реализацию минимальной коммерчески ценной функциональности (minimum marketable feature), которая представляет собой наибольшую ценность для бизнеса. Достигается это за счет ориентации на взаимодействие между командами бизнес-пользователей и разработчиков. При этом используется общий язык для такого взаимодействия, что сближает команды, и, в конечном счете, значительно снижает недопонимание в проекте, тем самым экономя время и убирая ненужный код и функциональность.

Набор инструментов

Для реализации приложения я выбрала следующий набор инструментов:

  • Apache Maven — фреймворк для автоматизации сборки проектов. Eго я выбрала исходя из соображений того, что он позволяет легко управлять зависимостями (благодаря поддержки транзитивных зависимостей и возможностью централизировано управлять зависимостями и плагинами — dependencyManagement, pluginManagement), версиями, обеспечивает зеркалирование зависимостей в локальный репозиторий, придает структуру приложению, благодаря которой большинство IDE (для разработки на Java) поддерживают этот фреймворк, и благодаря чему легко обеспечивается переход к процессу непрерывной интеграции приложения
  • JBehave — BDD фреймворк, который помогает автоматизировать приемочные тесты и поддерживает процесс разработки в BDD стиле. В этом фреймворке бизнес требования и их приемочные критерии описываются в виде, так называемых, пользовательских историй (user stories). Выбрала его, а не любой другой BDD фреймворк потому, что:
    • он хорошо документирован
    • лицензия позволяет его свободно использовать в проекте
    • у него открытый исходный код, который в случае проблем дает преимущество в отладки для нахождения workaround’а, если проблему еще не исправили в основном релизе
    • мне понравился подход и стиль, по которым пользовательские истории связываются с Java POJO объектами
    • у него есть библиотека, облегчающая взаимодействие с Selenium WebDriver API (jbehave-web-selenium), например ответственность за управление жизненным циклом браузера лежит на ней (см. Driving Web Behaviour
    • по результатам прохождения тестов генерируется отчет в достаточно детальной и удобочитаемой форме
  • Selenium WebDriver — фреймворк для автоматизации тестирования веб приложений. Выбрала его по нескольким причинам:
    • имеет богатое API для тестирования веб интерфейсов, написанных на HTML/CSS/JavaScript и которые нуждаются в проверки на различных популярных браузерах, таких как IE, Firefox, Google Chrome, Safari и других
    • один из самых популярных фреймворков на сегодняшний день, что в целом облегчает поиск различной информации по нем и, на мой взгляд, служит почвой для развития лучших практик в автоматизированном тестировании проектов
    • он бесплатен и распространяется под лицензией Apache License 2.0, что позволяет на нем писать собственное программное обеспечение и при этом не распространять на него исходного кода
    • у него открытый исходный код, который в случае проблем дает преимущество в отладки для нахождения workaround’а, если проблему еще не исправили в основном релизе
    • если нет подходящей версии браузера на одной машине, можно присоединиться к удаленной машине, где он есть, и выполнить на ней тест
    • тесты, написанные с его помощью можно исполнять в распределенной среде (Selenium-Grid), где разные тесты могут выполняться на разных машинах (все зависит от конфигурации)
    • Selenium WebDriver’ом можно работать на различных языках, таких как: Java, Python, .Net, Ruby, PHP, Perl, JavaScript
  • Spring. Этот фреймворк я выбрала для организации зависимостей в проекте
  • JUnit фреймворк — который служит платформой для написания и выполнения тестов. Выбрала его, потому что его функциональности вполне достаточно для покрытия бизнес требований, приведенных в качестве примера в приложении и также потому, что именно этот фреймворк идет в коробке с JBehave (имеется ввиду в виде транзитивной зависимости)
  • Hamcrest — фреймворк с большой коллекцией хорошо сочетаемых matcher’ов для проверки различных условий, причем, на мой взгляд, сочетаются эти matcher’ы гармонично и исключения выбрасываются по ним в удобочитаемой форме

Шаблон для проекта

После того, как я определилась с набором инструментов для реализации своей задумки я продолжила с того, что принялась гуглить уже готовые решения. И вот, по прошествии некоторого времени, мне попался один замечательный Maven Archetype, который почти удовлетворял мои пожелания. Называется он jbehave-web-selenium-java-spring-archetype, и находится в центральном репозитории Maven 2 (Maven 2 central repository). Maven Archetype — это инструмент, который позволяет легко и быстро сконфигурировать проект под себя по шаблонам существующего проекта. Для того, чтоб сконфигурировать проект под себя я воспользовалась командой:

mvn archetype:generate -Dfilter=org.jbehave.web:jbehave-web-selenium-java-spring-archetype

и далeе просто следовала инструкциям (см. Archetypes)

Что было мной проделано

  1. Адаптировала пользовательские истории под наш портал Prom.UA
  2. Перевела все зависимости проекта на использование Dependency Injection принципа на основе механизма аннотаций на базе Spring. Аннотации представляют собой метаинформацию для обозначений участков кода. Например: мы хотим, чтоб зависимость A в процессе инициализации получила зависимость B, для чего просто помечаем в зависимости A свойство, сеттер или конструктор, отвечающий за работу с зависимостью B, аннотацией @Autowired, и обоим зависимостям добавляем аннотацию @Component, чтоб обозначить их, как зависимости, управляемые Spring контейнером. На мой взгляд, применение аннотаций улучшает читабельность кода по той причине, что не нужно ходить в конфигурацию, чтоб понять, как будет построен объект во время его конструирования контейнером Spring
  3. Убрала фабрику PageFactory, так как в ней необходимость отпала после полноценного перехода на Spring Dependency Injection
  4. Убрала зависимость на fluent-selenium (обертка над Selenium WebDriver), чтоб уменьшить количество звеньев от кода приложения до браузера, тем самым сузив возможное разнообразие ошибок. Да и API Selenium WebDriver’а мне кажется вполне сносным и хорошо документированным. Хотя для тех, кто все же со мной не согласится, то можно его добавить в pom.xml (см. jbehave-web-selenium-java-spring-archetype maven archetype, там он используется), и тогда ваши обращения к WebDriver’у могут стать похоже на FluentInterface, о котором писал Мартин Фаулер
  5. Параметризировала сценарий promua_search.story так называемой таблицей с примерами (examples table), при которой в сценарии описываются шаги с отметками, а отметки во время выполнения подменяются на значения из таблицы, что убирает необходимость в повторном написании одного и того же сценария для разных входных данных. Детальней можно прочитать здесь: Parametrised Scenarios
  6. Добавила абстракцию над существующими PageObject’ами, которая позволяет осуществлять запросы за веб элементами через WebDriver к браузеру с использованием явных и не явных ожиданий для получения результата обращения. Тут, кстати, мне пришлось реализовать свой велосипед, так как существующие решения иногда отказывались работать по исключению NoSuchElementException. Придумала я реализовать это решение на основе кеширующего пула потоков и задач. Последние отправляю в пул на выполнение. На каждую задачу устанавливается время ожидания, интервал выполнения и локатор для поиска веб элемента. В целом, инициализация очень похожа на FluentWait (благодаря шаблону Builder, который я для себя открыла после прочтения о FluentInterface, ©Мартин Фаулер), но внутри реализация своя. Если результат обращения за веб элементом возвращается раньше, то задача завершается, и результат возвращается. Возможно это решение и не идеальное, но зато тесты перестали падать по исключению NoSuchElementException с теми же настройками ожидания и интервалом, что использовала во FluentWait (см. Class FluentWait). Почему такое происходит, я затрудняюсь сказать
  7. Добавила поддержку создания скриншота по случаю возникновения ошибки во время выполнения сценария путем объявления бина WebDriverScreenshotOnFailure в Spring контексте (файл конфигурации promua-steps.xml). Этого достаточно, так как мы создаем фабрику SpringStepsFactory в PromUaStories.stepsFactory, которая получает контекст Spring’а и в дальнейшем использует Spring бины из контекста для работы с JBehave аннотированным кодом (используя механизм Dependency injection), например, во время выполнения шагов (step’ов). Об этом можно прочитать здесь: Dependency Injection в JBehave
  8. Упорядочила зависимости в pom.xml (файл конфигурации Maven)

Spring бин — это объект, который управляется Spring’ом.

По поводу Spring хочу также добавить, что в promua-steps.xml определены два бина:

  • <context:annotation-config />
    — используется для включения механизма аннотаций у уже зарегистрированных бинов в контейнере Spring
  • <context:component-scan base-package="ua.prom"/>
    — используется для сканирования пакетов ua.prom*/** на предмет аннотаций над бинами, например такой как @Component с последующей регистрации такого бина в контейнере Spring

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

Как работать с проектом

  1. Для сборки проекта и последующим выполнением всех пользовательских историй нужно выполнить команду
    mvn clean install
  2. Для сборки проекта и последующим выполнением пользовательских историй, которые удовлетворяют фильтр по названию файла с пользовательской историей, нужно выполнить команду
    mvn clean install -DstoryFilter=promua_cart
  3. Для сборки проекта и последующим выполнением пользовательских историй, которые удовлетворяют фильтр по мета информации, нужно выполнить команду
    mvn clean install -Dmeta.filter="+category basic"

Тут я хотела бы сказать несколько слов по поводу мета информации. Построения соответствия между мета информацией и пользовательской историей происходит во время фазы integration-test (описано в pom.xml файле конфигурации Maven) и вызовом в этой фазе PromUaStoryMaps со списком мета фильтров (metaFilters). В результате этого, во время выполнения пользовательских историй выполняются только те, которые удовлетворяют критерию фильтра (см. Meta Matchers)

Просмотр результатов тестов

После выполнения тестов в директории target/jbehave/view будет создан файл, который называется reports.html. В этом файле описывается результат в виде таблице в разрезе сценариев, шагов и их результатов выполнения. Каждая запись в таблице соответствует пользовательской истории. В правой части таблице, в последней колонке, находятся ссылки. Кликая по ссылке вы перейдете к детальному отчету по выбранной пользовательской истории.

Структура проекта

  • ua.prom — пакет в котором определены сущности по конфигурированию контекста выполнения тестов. PromUaStoryMaps выполняет привязку мета информации к пользовательской истории. PromUaStories занимается конфигурированием контекста выполнения и непосредственно запуском пользовательских историй. По своей сути оба класса являются точкой входа (entry-point) приложения, которые используются JBehave’ом для настройки и запуска пользовательских историй
  • ua.prom.pages — пакет в котором определены сущности, реализованные в соответствии с шаблоном PageObject, используемых в шагах (step’ах) для абстракции и обеспечения лучшей организации кода. В классе PageObject вообщем-то и находится разработанный и спрятанный мной велосипед по работе с поиском веб элементов
  • ua.prom.steps — описаны сами шаги (step’ы). JournaledStoriesSteps выполняется после каждой пользовательской истории и выводит в лог журнал команд WebDriver’а (наследие от Maven Archetype для примера). LifecycleSteps — чистит карту покупателя перед каждой пользовательской историей (также наследие от Maven Archetype для примера)
  • src/main/resources — находятся ресурсы приложения. log4j.properties — файл свойств логгера, который пишет разного рода информацию в настроенный вывод (может быть файлом, консолью и др.). promua-steps.xml — файл конфигурации Spring, где я описала только те зависимости в виде бинов, которые не находят своего отображения в коде приложения (над ними невозможно поставить аннотации @Component, так как они подключены и используются в проекте как третьи зависимости)
  • src/main/stories — находятся текстовые файлы с пользовательскими историями (user stories)

В завершения своей статьи хотела бы еще добавить, что аннотацию @Component можно было бы и расширить до @Steps и использовать ее для аннотирования шагов (step’ов), и она тоже бы воспринималась родной Spring’у (я видела такой подход во многих проектах на GitHub), но я этого не стала делать, так как мне показалось, что людям, которые будут поддерживать этот код после меня, как мне кажется, будет более очевидней, какой жизненный цикл сущности под аннотацией @Component, нежели под аннотацией @Steps. Конечно же, все это при условии, что никакой другой ответственности не будет повешено на аннотацию @Steps. В противном же случае, возможно, ее следует ввести (и при этом не забыть задокументировать для потомков).

Спасибо всем за внимание.
Хороших праздников и хорошего Нового Года!

Полезные ресурсы

  1. Хороший tutorial по Spring: Spring Framework Tutorial
  2. Еще один хороший tutorial по Spring: Spring Tutorial
  3. Хороший tutorial по Maven: Maven Tutorial
  4. Еще один хороший tutorial по Maven: Maven Tutorial
  5. Официальный ресурс по JBehave: JBehave
  6. Презентация по JBehave: BDD with JBehave and Selenium
  7. Официальный ресурс по Selenium WebDriver: Selenium WebDriver
  8. Хороший tutorial по JUnit: JUnit Tutorial
  9. Хороший tutorial по Hamcrest: The Hamcrest Tutorial
  10. BDD: Behavior-driven development
  11. Minimum Marketable Feature: Incremental funding methodology
  12. Описание шаблона PageObject: Page Objects
  13. Описание фабрики: Factory (software concept)
  14. Описание шаблона Builder: The builder pattern in practice
  15. Описание шаблона Dependency injection: Dependency injection

(Вячеслав Артемчук) #2

Уважение к prom.ua поднялось на 100500 пунктов!


(biomaks) #3

Круто! правда не очень понял как удалось уйти от Page object с помощью Dependency injection.


(Mykhailo Poliarush) #4

@irinkav у меня еще возник вопрос удалось внедрить ли это все в жизнь в реальности, потому что насколько я знаю в Prom.ua используется python и автотесты там тоже писались на python.


(heartwilltell) #5

В теме на доу написано что в продакшене не применяется


(Mykhailo Poliarush) #6

Ну посмотрим тогда, ведь если есть решение, значит и будет мотивация его внедрить.