Русский
Русский
English
Статистика
Реклама

Cucumber

Хамелеон, которого мы создали и приручили

01.12.2020 14:07:50 | Автор: admin

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


Его появлению предшествовало 15 лет практики тестирования в компании IBS AppLine* (лидера российского рынка аутсорсинга услуг тестирования по версии TAdviser за 2018 год на минуточку!). На базе этих знаний и экспертизы мы задались целью ускорить старт проектов, повысить качество тестирования, упростить введение в работу новичков. Решение должно позволить автоматизировать функциональное тестирование веб, мобильных, десктоп-приложений и различных видов API.




В общем, исследовательский центр IBS AppLine Innovation** суммировал весь опыт компании и создал Хамелеон инструмент для автоматизации функционального тестирования. Делался с использованием языка программирования Java и инструментов Cucucmber, Selenium, Appium, Winium, Spring. Этот фреймворк:


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

Теперь подробнее о функционале



Как устроен Хамелеон


Вот несколько особенностей нашего фреймворка:


  • Это многомодульный maven-проект, который включает модули тестирования web, мобильных приложений, SAP-приложений, баз данных, Rest API и web-сервисов. Необходимые модули подключаются к проекту.
  • Мы взяли проверенные временем оpen source-инструменты, в том числе Selenium, Appium, Winium, и удачно их объединили в одном решении.
  • Для ускорения разработки автоматизированных тестов мы создали плагин для среды разработки IntelliJ IDEA. Получился полезный инструмент разработчика автоматизированных тестов. Плагин дополняет возможности IDEA, делая ее полноценным рабочим местом.
  • Для удобства разработки автоматизированных тестов для web-приложений мы создали расширение для браузера Google Chrome, которое позволяет добавлять элементы тестируемого приложения в проект прямо из браузера и имеет возможность записи автоматизированного теста в формате Cucumber методом Record&Playback.

Open source-библиотеки


В основе инструмента лежат оpen source-библиотеки Selenium, Appium, Winium, UIAutomation. Для разработки самих тестов используется фреймворк Cucumber, который позволяет писать на русском языке. Такой формат понятен и ручным тестировщикам, и не имеющим отношения к написанию конкретного теста специалистам автоматического тестирования, что снижает порог вхождения сотрудников в проект. Всему, что происходит в Cucumber, соответствуют свои Java-команды, так что при необходимости тесты можно разрабатывать на чистой Java.



Простота установки


Для разработки автоматизированных тестов с использованием Java на рабочую станцию устанавливаются Java JDK, Apache Maven/Gradle, IntelliJ IDEA, плагины для Intellij IDEA, Git Client. У начинающих специалистов это занимает много времени. Мы упростили процесс, разработав общий инсталлятор, который представляет собой .exe-файл с возможностью выбора необходимого ПО для установки на рабочее место:




Начало разработки


Для разработки автоматизированных тестов можно использовать готовые стартеры проектов. Стартеры это архетипы maven, которые содержат готовую структуру проекта. Они хранятся во внутреннем репозитории компании. При создании проекта в IntelliJ IDEA нужно лишь выбрать необходимые. Например, для разработки тестов, которые взаимодействуют с web-приложением и REST, необходимо подключить модули chameleon-selenium-cucumber и chameleon-rest-cucumber.




Немного о фреймворке


В основном автоматизированные тесты разрабатываются с помощью инструмента Cucumber, который позволяет писать тесты на русском языке. Автоматизированный тест состоит из следующих блоков:


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

Пример автоматизированного теста:



# language: ru# Тестовые данные:  # $ФИО Иванов Иван Иванович  # $ссылка https://www.appline.ru/Функция: Заявка на обучение  Сценарий: Заявка на обучение    * страница "Главная" загружена    * выбран элемент коллекции "Меню" с параметрами:      | field        | operator | value             |      | Наименование | равно    | Start IBS AppLine |    * нажатием на кнопку "Наименование" загружена страница "Start IBS AppLine"    * поле "Имя" заполняется значением "#{ФИО}"    * поле "Ссылка на резюме" заполняется значением "#{ссылка}"    * выполнено нажатие на "Отправить"    * поле "Required field" видимо

Существуют шаблоны для работы с переменными: операции с датами, математические операции, выполнение кода и т.д. Например, для работы с текущей датой используется шаблон #now{дата; исходный_формат; смещение}. Предположим, в автоматизированном тесте необходимо проверить дату операции, которая была только что осуществлена. Такая проверка будет выглядеть так:


* значение поля "Дата операции" равно "#now{dd.MM.yyyy HH:mm}"

А, например, создать отложенную операцию, которая исполнится завтра:


* поле "Дата операции" заполняется значением "#now{dd.MM.yyyy;+1d}}"

Выполнить программный код можно с использованием шаблона #script{RESULT=выражение_java}. Например, удаление лишних символов в переменной будет выглядеть следующим образом:


* в переменной "Номер_счета" сохранено значение поля "Номер счета"* значение поля "Номер счета" равно "#script{RESULT = Номер_счета.replaceAll("", "")}"

В нашем фреймворке разработаны основные Cucumber-шаги, которые напоминают шаги из ручных тестовых сценариев. Они описывают действия, которые человек может совершить с тестируемым приложением: нажать на элемент, ввести значение в поле, прочитать значение, сравнить значения и т.д. Таких шагов примерно 30. Для часто повторяемых операций такие шаги объединяются в более крупный шаг.


Например, авторизация в приложении может описываться в 3 шага:


Когда заполняются поля:  | field  | value        |  | Логин  | test@test.ru |  | Пароль | 123123       |И выполнено нажатие на "Войти"Тогда страница "Главная" загружена

Или на основе этих шагов создается 1 шаг (пароль в этом случае хранится в отдельном файле с пользователями):


Дано авторизован пользователь "test@test.ru"

Все размеченные элементы тестируемого приложения имеют свой тип, например, Button, TextInput, Combobox, Checkbox и т.д., это позволяет использовать одни и те же Cucumber-шаги для работы с разными типами элементов. Например, есть шаг:


* поле "field" заполяется значением "value"

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



АРМ тестировщика или разработка теста


Стандартное представление проекта для разработки тестов содержит много классов и вспомогательных файлов, которые очень редко нужны при разработке самого автоматизированного теста. Чтобы упростить этот процесс мы постарались оградить тестировщика от этой информации и разработали плагин для Intellij IDEA. Его интерфейс стал рабочим местом тестировщика, и содержит следующие разделы:


  • список тестов,
  • объектный репозиторий,
  • список доступных действий,
  • настройки запуска,
  • документацию,
  • различные автокомплиты, ускоряющие процесс создания теста.


Список тестов


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




Репозиторий объектов


Традиционный и очень популярный инструмент разработчика автоматизированных тестов шаблон Page Object Pattern. При его использовании элементы тестируемого приложения описываются в отдельных java-классах, которые соответствуют страницам тестируемого приложения. На крупных проектах таких Page Object-классов становится очень много. Кроме того, иногда они еще и называются беспорядочно. В результате для больших проектов такой подход не очень удобен: неизбежно дублирование работы на проектах работает много специалистов, приходится расшифровывать работу коллег и анализировать разметку элементов, а это не всегда проходит гладко.


Поэтому мы создали репозиторий объектов тестируемого приложения. Он хранит все его элементы не в классах, а в одном или нескольких xml-файлах, а плагин для IntelliJ Idea показывает эти xml-файлы в виде древовидной структуры, в которой узлами являются страницы тестируемого приложения. Вместо разномастных английских названий мы используем русский язык, что упрощает работу тестировщиков, так им легче находить размеченные страницы и элементы, а также добавлять новые.


Приведем конкретный пример. Для одного крупнейшего отечественного банка (название по понятным причинам не называем) нами было разработано 20 автотестов, использовавших 78 страниц тестируемых приложений (достаточно длинный бизнес-процесс). В обычных условиях тестировщикам пришлось бы создать 78 java-классов и разметить на них более 2000 элементов. С Хамелеоном мы всю эту громаду открываем в древовидной структуре, в которой их легко и просто просматривать, перетаскивать, компоновать.




Существует два способа добавления элементов в репозиторий.


Добавление в среде разработки IntelliJ IDEA:



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


Также есть возможность добавлять элементы прямо из тестируемого приложения с помощью созданного нами расширения для браузера Google Chrome. Расширение самостоятельно определяет тип элемента, его наименование и подставляет локатор. Для этого достаточно навести мышкой на элемент. Расширение синхронизируется с плагином в IntelliJ IDEA, поэтому все, что происходит в браузере, передается в среду разработки. Так можно наполнять репозиторий объектов, проходя ручной тест в браузере. С помощью расширения можно проверить корректность локатора уже существующего в репозитории элемента.




Чтобы не было дублирования элементов, существует тип элемента Block. Например, у нас в тестируемом приложении есть блок Меню, и он доступен на всех страницах приложения: в этом случае в репозитории элементов мы размечаем его как страницу Меню, содержащую элементы меню, а на других страницах добавляем его как элемент с типом Block. Таким образом, получается переиспользование элементов, которые встречаются более чем на одной странице.



Разработка автоматизированного теста


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


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


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




Второй способ разработки автоматизированного теста использование репозитория шагов. В плагине в древовидной структуре показываются шаги, которые можно перетащить методом Drag&Drop, как показано ниже. При использовании такого варианта создания автоматизированного теста тоже присутствуют подсказки элементов и переменных. Таким вариантом обычно пользуются начинающие сотрудники, которым проще искать необходимые шаги в репозитории, а не java-классах.




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


Например, пользователь логинится на сайте, нажимая для этого на кнопку Логин. Рекордер записывает шаг * выполнено нажатие на поле Логин. Пользователь заполняет поле Логин значением User, рекордер записывает шаг * поле Логин заполняется значением User и так далее. После этого получившийся автотест можно скопировать и вставить в среду разработки для редактирования. Плагин автоматически, на основе объектного репозитория, определяет, на какой странице находится пользователь, и выполняет поиск размеченных элементов. Если элемента в репозитории нет, то будет предложено его добавить.


Пока рекордер существует только для браузера. В процессе разработки находится рекордер для SAP GUI.



Запуск и отладка


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


  • подсветку элементов будут выделяться элементы, с которыми взаимодействует тест;
  • запись видео в случае ошибки к отчету будет прикреплено видео прохождения автоматизированного теста;
  • конфигурацию запуска браузер, в котором будет выполнен тест;
  • режим запуска с графическим интерфейсом или headless-режиме (без графического интерфейса);
  • закрытие браузера после теста удобно при разработке длинных тестов или локализации ошибок;
  • подключение к открытому браузеру чтобы начать автоматизированный тест не с начала, а с выбранного места, подключаясь к открытому браузеру.



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


Чтобы отслеживать ход выполнения теста, мы разработали консоль, куда перенаправляется весь лог с IntelliJ IDEA. Это позволяет контролировать процесс и понимать, что сейчас выполняет автоматизированный тест. Консоль отображается поверх содержимого экрана и не мешает выполнению теста. Есть возможность настраивать формат вывода в консоль (размер, шрифт, цвет и т.д.).




Документация


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




Тестирование API


Для тестирования API (REST и SOAP) также используется объектный репозиторий. В этом случае страницами будут endpoint, а элементами заголовки и тело запроса.




Во фреймворке реализованы базовые действия с API, при наборе действий происходит автоподстановка параметров вызова.




Отчет о выполнении автоматизированных тестов


В качестве инструмента отчетности был выбран Allure. При запуске тестов из среды разработки IntelliJ IDEA аllure-отчет можно открыть прямо из плагина.


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



Результаты


Хамелеон помог нам не на словах, а на деле.


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


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


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


Наконец, мы получили еще одно преимущество на отечественном рынке: кодирование на русском языке легче освоить. Для этого у нас есть корпоративный университет, где мы обучаем будущих тестировщиков писать автотесты с нуля буквально за месяц. И в этом очень важную роль играет Хамелеон: с его помощью мы закладываем общую базу, на нем обязательно проводим несколько занятий по разработке тестов. Ежемесячно через этот курс проходит 5-10 человек, имеющих базовые знания языка программирования Java.



Планы на будущее


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





* IBS AppLine лидер российского рынка услуг тестирования и обеспечения качества программного обеспечения, разработчик решений для автоматизации тестирования. Компания была создана в 2001 году, в штате более 700 специалистов, общее количество проектов превысило 1500.


** IBS AppLine Innovation (ранее Аплана АйТи Инновации) была создана в декабре 2017 года как центр исследований и разработки компании IBS AppLine (ранее Аплана). Основу команды составили ее собственные опытные инженеры и разработчики.

Подробнее..

Cucumber и BDD, пишем ui авто тесты на iOS

08.10.2020 12:16:26 | Автор: admin

Предисловие

Привет, Хабр! В данной статье-мануале я хочу рассказать о базовых функциях такого фреймворка как Cucumber и его применение для создания ui авто тестов на мобильных iOS устройствах.

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

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

Несколько слов о Gherkin, Cucumber и BDD

Gherkin представляет из себя структурированную манеру написания документации для PO, бизнес-аналитиков и тестировщиков. Академическое определение Gherkinговорит, что это человеко-читаемый язык для описания поведения системы, каждая строчка начинается с одного из ключевых слов (Given-When-Then-And) и описывает одно из предусловий/шагов/результатов.

Cucumber - это инструмент, используемый для выполнения behavior driven (BDD) сценариев, написанных на языке Gherkin.

BDD (behavior driven development) - методология разработки ПО, основной идеей которой является составление требований к продукту в формате понятых не-специалисту поведенческих сценариев. Пример BDD сценария:

Scenario: Login with PINGiven the app is runningAnd I'am registered userAnd I see Login screenWhen I enter 4-digits PINThen I am logged in

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

Разворачиваем Cucumber

На сайте Cucumber поддержка iOS находится в любопытном статусе semi-official (полу-официальный?) поэтому процесс установки и настройки фреймворка местами весьма нетривиален.

  • Cucumber - это СocoaPod библиотека, поэтому начинаем с нее. Открываем терминал и устанавливаем CocoaPod

    sudo gem install cocoa pods

  • переходим в свой проект и создаем подфайл

    pod init

  • заходим в созданный подфайл. Проверяем, что в нем есть следующее:

source 'https://github.com/CocoaPods/Specs.git'platform :ios, '11.0'use_frameworks!inhibit_all_warnings!def test_pods  pod 'Cucumberish'endtarget НАЗВАНИЕ_ВАШЕГО_ПРОЕКТАCucumberTests do  test_podsend

Если этой записи нет - добавляем её руками, предварительно удалив всё из файла. Обратите внимание, что в таргете фигурирует название вашего проекта

  • устанавливаем XCFit

    sudo gem install xcfit

  • открываем Xcode, добавляем к проекту новый таргет, используя появившийся шаблон cucumberish bundle. В проекте появятся папка НазваниеВашегоПроектаCucumberTests с дефолтными файлами. Там же необходимо самостоятельно создать папку Features

  • идем в build phases таргета CucumberTests, удаляем дубликаты Copy Bundle Resources, Compile Sources и Link Binary With Libraries

  • закрываем Xcode, устанавливаем поды

    pod install

  • в проекте появится .xcworkspace файл, открываем его. Зачастую на этом шаге отваливаются стандартные файлы из папок Screens, Step Definitions и Supporting Files. Если это произошло - добавляем их обратно руками через Add Files to.

    Почти готово, мы в шаге от завершения установки Cucumber!

  • на момент написания этой статьи (осень 2020) из коробки фреймворк не собирается из-за нескольких ошибок в коде. Возможно, эти проблемы будут неактуальны. Через поиск в Xcode находим и правим следующие строки:

    • добавляем @objc перед class func CucumberishSwiftInit()

    • зменяем var elementQurey на var elementQuery

    • заменяем expectedMenuCount: uInt = uInt(menuCount)! на expectedMenuCount: Int = Int(menuCount)!

    • заменяем expectedCellCount: uInt = uInt(cellCount)! на expectedCellCount: Int = Int(cellCount)!

Вот теперь все. Жмем +U для запуска тестов. Если все сделано правильно, проект соберется, а в логе мы увидим сообщение Tests successfully executed 0 from 0. Это значит, что фреймворк успешно отработал, но не запустил ни одного теста, что не удивительно, так как мы еще не написали ни одного сценария.

Фреймворк "из коробки"

По умолчанию Cucumber имеют следующую структуру:

  • папка Features - в ней хранятся файлы с разрешением .feature, они содержат в себе один или несколько BDD сценариев. Каждый сценарий, написанный на Gherkin, состоит из набора строк, последовательно выполняемых при работе теста

  • <название проекта>CucumberTests.swift файл в корне фреймворка. Содержащий код, выполняемый для Given шагов, задает предусловия каждого теста. По умолчанию файл будет содержать шаг для запуска приложения. Также файл содержит ряд настроек, к примеру, управление тэгами, но о них чуть позже

  • папка Screens - в ней хранятся .swift файлы, содержащие локаторы, по которым можно обращаться к инспектируемым элементам приложения

  • папка Step Definitions - в ней хранятся .swift файлы содержащие код, выполняемый в шагах тестов

  • папка Common - в ней хранится commonStepDefinitions.swift файл, содержащий в себе код, который может выполняться для простых проверок типовых элементов (наличие объектов на экране, нажимаемость кнопок и т.п.)

Для удобства организации шагов и сценариев в соответствующих папках фреймворка можно создавать дополнительные файлы. Все .feature файлы, помещенные в папку Features, будут подтягиваться в тестовые наборы автоматически, а файлы с шагамипотребуется дополнительно вызывать в beforeStart функции CucumberishSwiftInit()

Что происходит при запуске теста?

Фреймворк установлен, теперь мы хотим создать свой первый тест. Для того, чтобы это было проще сделать, надо понимать, что будет происходить c Xcode после того, как вы нажмете +U.

А происходить будет следующее:

  • фреймворк соберет проект на выбранном девайсе/эмуляторе

  • фреймворк построчно распарсит первый сценарий из первого фича-файла

  • все первые Given и And строки будут рассматриваться как предусловия теста. Они могут быть как совсем простыми и состоять из единственного Given условия, так и комплексными Given-And-And- наборами строк

Простой шаг-предусловиеПростой шаг-предусловие
  • фреймворк отправится в корневой swift файл за кодом, выполняемым в этих шагах. Если точнее, то для простого предусловия выше будет выполнен следующий код:

Шаг The app is running является первым и обязательным почти для любого сценария, так как в нем происходит запуск трестируемого приложения.

  • как только будут пройдены все Given шаги и дело дойдет до первой When или Then строки, предусловия будут считаться выполненными. За кодом для выполнения последующих строк фреймворк будет обращаться в .swift файлы из папки Step Definitions

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

Пишем свой первый тест

Итак, имея базовое представление о том, как работает фреймворк мы понимаем, что именно должно быть сделано для создания нашего первого теста:

  • создаем feature файл в папке Features. В начале файла обязательно должна быть общая информация описывающая функционал по шаблону:

Feature:In order to As a I want to 
  • пишем тестовый сценарий в feature файле, используя синтаксис Gerkin

  • в корневом swift файле раскрываем Given шаги этого сценария

  • в step definition файле раскрываем остальные шаги

Особенности написания Given шагов

Упомянутого выше предусловия the app is running самого по себе почти всегда будет недостаточно. Если точка входа в тест находится не на стартовой страничке, а где-то глубже, то удобно использовать комплексные Given-And-And- предусловия. При помощи еще одной или нескольких строк, мы можем привести приложение к нужному для конкретного теста состоянию.

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

Итак, из предусловия сценария видно, что после запуска приложения я хочу взаимодействовать с ним как зарегистрированный пользователь, хочу видеть экран My credentials, и при этом экран должен быть пустым и не содержать ни одной сущности.

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

  • запускаем приложение

  • если после запуска мы видим страницу регистрации, то регистрируемся, нажав на кнопку Get started. Ждем, пока прогрузится экран для установки пинкода, задаем пин 0000, вводим его повторно для подтверждения регистрации

Если после запуска мы видим НЕ страницу регистрации, значит, регистрация была произведена в предыдущем тесте, и приложение, сохранив этот состояние, направит нас сразу на экран логина. В этом случае нам остается лишь залогиниться единожды введя пин 0000.

В конце шага также есть UIInterruptionMonitor, он необходим, чтобы обработать системный диалог с запросом на разрешение биометрического логина (faceid или отпечаток пальца) при самом первом запуске приложения.

  • Проверяем, что после регистрации/логина приложение прогрузилось, и мы находимся на экране My credentials. Простой ассерт, в котором мы ожидаем экран

  • Проверяем, что на экране в табличке credentialList нет сущностей, если они остались с предыдущих тестов, удаляем их одну за одной. Для этого тапаем по первой ячейке в таблице, вызываем меню действий, тапаем по кнопке "Delete" и подтверждаем кнопкой "Delete credential". Повторяем эти действия пока первая ячейка в таблице не перестанет существовать

В результате предусловия выполнены. Мы имеем запущенное приложение, ожидающее дальнейших шагов на пустом экране My credentials.

Несколько слов о тестовых шагах и CommonStepDefinitions

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

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

Допустим, в вашем приложении есть условный объект Menu, на нем находятся две стандартные кнопки Confirm и Deny, а также текст Please confirm. Для того, чтобы проверить отображение этого объекта, кнопок и текста, не обязательно в step definitions детализировать код для четырех разных шагов. Достаточно просто в сценарии написать эти шаги в подходящем под CommonStep формате:

And I see the "Menu" viewAnd I see "Confirm" buttonAnd I see "Deny" buttonAnd I see "Please confirm" text

При выполнении теста все эти строки будут определены как common шаги, а точнее, как один единственный шаг:

Использование common шагов позволяет здорово сократить количество кода, необходимого для простых проверок или действий. Но надо понимать, что этот метод не всегда подходит для тестирования кастомных элементов из-за сложных путей их обнаружения. В этом случае удобнее всего пользоваться обычными step definitions и обращаться к этим элементам через accessibility identifier.

Запускаем тесты

После того, как один или несколько BDD сценариев написаны и ко всем их строкам существует definition, можно запускать тестовый прогон комбинацией +U. В случае, если необходимо запустить только часть тестов, можно воспользоваться тегами, отметив ими желаемые сценарии в фича файлах (или фича файлы целиком) и перечислив теги для запуска в executeFeatures корневого .swift файла.

По умолчанию состояние приложения после каждого теста не обнуляется, так что если в конкретном сценарии подразумевается создание какого-либо объекта, сущности, записи в памяти телефона или чего-либо еще, то в последующем тесте мы этот объект увидим.

Из этого можно извлечь пользу. К примеру, на нашем проекте из общего количества авто-тестов в 50+ штук необходимо всего 5 тестов на регистрацию. После прохождения этих 5-и тестов состояние регистрации сохраняется и последующие 45 тестов начинаются уже с логина, минуя десяток тапов по кнопкам и пару экранов. Тем самым, мы экономим примерно 10 секунд времени от каждого теста, не выполняя одни и те же действия, уже протестированные ранее.

Обратная сторона медали - периодически требуется очищать приложение от различных сущностей в предусловиях тестов (как было показано выше на примере шага I have no credentials). Для этого приходится писать довольно объемные шаги, но в моем случае такой существенный выигрыш времени стоит того.

Отчет

После выполнения всех тестов будет сформирован стандартный Xcode отчет. Тесты в нем группируются по фича файлам. Для любого шага можно просмотреть детализацию вплоть до вызываемых методов.

В случае падения теста тут же можно будет увидеть подробный лог и скриншоты. Этот инструмент очень удобен при написании и отладке тестов на новые фичи.

Когда начинается магия?

Сперва создание и поддержка cucumber тестов казались мне довольно трудоёмким занятием, фреймворк выглядел медленным и неудобным, а BDD сценарии излишне формализованными. Но после десятка внедренных тестов я полностью изменил свое мнение.

Одна из самых полезных фишек кукумбера - переиспользование отдельно взятых шагов в любом месте, где это допустимо. Максимальное дробление сценариев на мельчайшие части, так раздражавшее поначалу, спустя 3-4 спринта привели к формированию внутри фреймворка большого пула разных шагов. Все эти предусловия, действия и результаты при грамотном написании должны работать независимо друг от друга и иметь одинаковые точки входа-выхода, в этом случае их можно переиспользовать, комбинировать и на лету собирать из них новые авто-тесты просто написав BDD-сценарий. В моей текущей работе бывали случаи, когда создание авто-тестов на новый функционал просто сводилось к написанию BDD сценария из уже существующих шагов. Новый авто-тест без программирования? Фантастика? Так вот с cucumber это действительно возможно.

Если добавить к этому то, что при разработке по BDD методологии сценарии для вас пишет PO и пишет их точь-в-точь как вам надо, то получается совсем утопическая вселенная, где тестировщику остается только скопипастить текст из Jira в фича-файл и получить работающий автотест.

Естественно, реальность всё-таки вносит свои корректировки, и PO будет иметь отличный от тестировщика взгляд на описание фичи, чаще всего, сценарии приходится глубоко редактировать, дополняя деталями или пропущенными шагами, примерять на них стандартные техники тест дизайна. И без добавления кода в step definitions тоже никак не обойтись.

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

Надеюсь, эта статья помогла вам узнать чуть больше о таком не самом распространенном, но очень интересном звере в мире мобильных UI авто-тестов как Cucumber. Если у вас есть вопросы, жду их в комментариях, постараюсь все прочитать и на все ответить.

Подробнее..

Fast-Unit или декларативный подход к юнит-тестам

03.09.2020 16:16:34 | Автор: admin

Всем привет! Меня зовут Юрий Скворцов, наша команда занимается автоматизированным тестированием в Росбанке. Одной из наших задач является разработка средств для автоматизации функционального тестирования.

В этой статье я хочу рассказать о решении, которое задумывалось как небольшая вспомогательная утилита для решения прочих задач, а в итоге превратилось в самостоятельный инструмент. Речь пойдет о фреймворке Fast-Unit, который позволяет писать юнит-тесты в декларативном стиле и превращает разработку юнит-тестов в конструктор компонентов. Проект разрабатывался в первую очередь для тестирования нашего основного продукта -Tladianta единого BDD-фреймворка для тестирования 4-х платформ: Desktop, Web, Mobile и Rest.

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

На первом этапе мы попытались воспользоваться готовыми инструментами, такими как assertJ и Mockito, но быстро столкнулись с некоторыми техническими особенностями нашего проекта:

  • Tladianta уже использует JUnit4 как зависимость, что делает сложным использование другой версии JUnit и усложняет работу с Before;
  • Tladianta содержит компоненты для работы с различными платформами, в ней есть множество сущностей крайне близких с точки зрения функционала, но с разной иерархией и разным поведением;
  • многие компоненты требуют значительной предварительной настройки и могут фонить (влиять на результаты других тестов) при массовом прогоне;
  • некоторые компоненты фреймворка используют другие активно развивающиеся зависимости, и, к сожалению, мы далеко не всегда можем положиться на их надежность и гарантии обратной совместимости, а значит проверять нужно и их работу;
  • некоторую функциональность фреймворка приходится полностью блокировать при запуске юнит-тестов (например, запуск Appium во время тестов крайне нежелателен, тем более, что он закончится ошибкой, поскольку сервер для него никто не поднимал);
  • необходимость толстых обвязок, а также реализации ожиданий: Mockito тут нам помочь полноценно не смог.

Первый подход к снаряду


Изначально, когда мы только научились подменять драйвер, создавать фейковые элементы селениума и написали базовую архитектуру для тестовой обвязки, тесты выглядели примерно так:

@Testpublic void checkOpenHint() {    ElementManager.getInstance().register(xpath,ElementManager.Condition.VISIBLE,ElementManager.Condition.DISABLED);    new HintStepDefs().open(("Подсказка");    assertTrue(TestResults.getInstance().isSuccessful("Open"));    assertTrue(TestResults.getInstance().isSuccessful("Click"));}@Testpublic void checkCloseHint() {    ElementManager.getInstance().register(xpath);    new HintStepDefs().close("Подсказка");    assertTrue(TestResults.getInstance().isSuccessful("Close"));    assertTrue(TestResults.getInstance().isSuccessful("Click"));}

Или вообще вот так:

@Testpublic void fillFieldsTestOld() {    ElementManager.getInstance().register(ElementManager.Type.CHECK_BOX,"//check-box","",ElementManager.Condition.NOT_SELECTED);        ElementManager.getInstance().register(ElementManager.Type.INPUT,"//input","");        ElementManager.getInstance().register(ElementManager.Type.RADIO_GROUP, "//radio-group","");        DataTable dataTable = new Cucumber.DataTableBuilder()                .withRow("Чекбокс", "true")                .withRow("Радио", "not selected element")                .withRow("Текстовое поле", "text")                .build();        new HtmlCommonSteps().fillFields(dataTable);        assertEquals(TestResults.getInstance().getTestResult("set"), ElementProvider.getInstance().provide("//check-box").force().getAttribute("test-id"));        assertEqualsTestResults.getInstance().getTestResult("sendKeys"), ElementProvider.getInstance().provide("//input").force().getAttribute("test-id"));        assertEquals(TestResults.getInstance().getTestResult("selectByValue"), ElementProvider.getInstance().provide("//radio-group").force().getAttribute("test-id"));    }

В коде выше найти то, что именно тестируется, несложно, как и разобраться в проверках, но кода огромное количество. Если включить сюда софт проверки и описания ошибок, то читать станет очень сложно. А мы всего лишь пытаемся проверить, что метод вызвался у нужного объекта, при том что реальная логика проверок крайне примитивна. Для того чтобы написать такой тест, надо знать про ElementManager, ElementProvider, TestResults, TickingFuture (обертка, чтобы реализовать изменение состояния элемента в течении заданного времени). Эти компоненты отличались в разных проектах, мы не успевали синхронизировать изменения.

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

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

Меняем философию


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

@IExpectTestResult(errDesc = "Не был вызван метод set", value = "set",expected = "//check-box", convertedBy = Converters.XpathToIdConverter.class, soft = true)@IExpectTestResult(errDesc = "Не был вызван метод sendKeys", value = "sendKeys", expected = "//input", convertedBy = Converters.XpathToIdConverter.class, soft = true)@IExpectTestResult(errDesc = "Не был вызван метод selectByValue", value = "selectByValue",expected = "//radio-group", convertedBy = Converters.XpathToIdConverter.class, soft = true)@Testpublic void fillFieldsTestOld() {    ElementManager.getInstance().register(ElementManager.Type.CHECK_BOX, "//check-box", "",ElementManager.Condition.NOT_SELECTED);    ElementManager.getInstance().register(ElementManager.Type.INPUT, "//input", "");    ElementManager.getInstance().register(ElementManager.Type.RADIO_GROUP, "//radio-group", "");    DataTable dataTable = new Cucumber.DataTableBuilder()            .withRow("Чекбокс", "true")            .withRow("Радио", "not selected element")            .withRow("Текстовое поле", "text")            .build();    runTest("fillFields", dataTable);}

Что изменилось?

  • Проверки были делегированы отдельному компоненту. Теперь не надо знать о том, как хранятся элементы, результаты тестов.
  • Что не менее важно: errDesc является обязательным полем, так что теперь даже не знакомый с кодом человек может сразу увидеть суть проверки.
  • Исчез конструктор, а определить при ревью, что именно проверяется, стало проще это всегда один и тот же метод runTest, теперь уже не требуется вникать в код, чтобы понять какой метод проверяется.
  • Невозможно перепутать ожидаемое и реальное значение.
  • Софт-проверки теперь определяются просто параметром аннотации, так что использовать их становится гораздо удобнее.

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

@IGenerateElement(type = ElementManager.Type.CHECK_BOX)@IGenerateElement(type = ElementManager.Type.RADIO_GROUP)@IGenerateElement(type = ElementManager.Type.INPUT)@Test@IExpectTestResult(errDesc = "Не был вызван метод set", value = "set", expected = "//check-box", convertedBy = Converters.XpathToIdConverter.class, soft = true)@IExpectTestResult(errDesc = "Не был вызван метод sendKeys", value = "sendKeys", expected = "//input", convertedBy = Converters.XpathToIdConverter.class, soft = true)@IExpectTestResult(errDesc = "Не был вызван метод selectByValue", value = "selectByValue",expected = "//radio-group", convertedBy = Converters.XpathToIdConverter.class, soft = true)public void fillFieldsTest() {    DataTable dataTable = new Cucumber.DataTableBuilder()            .withRow("Чекбокс", "true")            .withRow("Радио", "not selected element")            .withRow("Текстовое поле", "text")            .build();    runTest("fillFields", dataTable);}

Теперь код теста превратился в полностью шаблонный, параметры явно видны, а вся логика вынесена в шаблонные компоненты. Дефолтные свойства позволили убрать пустые строки и дали широкие возможности для перегрузок. Этот код почти соответствует BDD-подходу, предусловие, проверка, действие. К тому же, из логики тестов вылетели все обвязки, больше не нужно знать про менеджеры, хранилища тестовых результатов, код прост и легко читаем. Поскольку аннотации в Java почти не кастомизируются, мы ввели механизм конвертеров, которые из строки могут получать итоговый результат. Этот код не только проверяет сам факт вызова метода, но и id элемента, который его выполнил. Почти все существовавшие на тот момент тесты (более 200 единиц) мы достаточно быстро перевели на эту логику, приведя их к единому шаблону. Тесты стали тем, чем они должны быть документацией, а не кодом, так мы пришли к декларативности. Именно этот подход лег в основу Fast-Unit декларативность, самодокументируемость тестов и изоляция тестируемого функционала, тест полностью посвящен проверке одного тестируемого метода.

Продолжаем развитие


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

  • Package-generate отработка аннотаций, связанных с package-info. Компоненты, связанные с ними, обеспечивают загрузку конфигураций и общую подготовку обвязки.
  • Class-generate отработка аннотаций, связанных с классом теста. Здесь выполняются конфигурационные действия, относящиеся к фреймворку, адаптируя его к подготовленной обвязке.
  • Generate отработка аннотаций, связанных с самим методом теста (точкой входа).
  • Test подготовка инстанса и выполнение тестируемого метода.
  • Assert выполнение проверок.

Обрабатываемые аннотации описываются примерно так:

@Target(ElementType.PACKAGE) //аннотация является пакетной@IPhase(value = "package-generate", processingClass = IStabDriver.StabDriverProcessor.class,priority = 1) //указываем фазу и обработчик (обычно обработчик регистрируется в том же классе)public @interface IStabDriver {    Class<? extends WebDriver> value(); //здесь принимаем класс драйвера, который будет загружен вместо настоящего    class StabDriverProcessor implements PhaseProcessor<IStabDriver> { //класс обработчик        @Override        public void process(IStabDriver iStabDriver) {            //подмена драйвера фейковым        }    }}

Особенность Fast-Unit в том, что жизненный цикл можно переопределить для любого класса он описывается аннотацией ITestClass, которая предназначена для указания тестируемого класса и фаз. Список фаз указывается просто как строковый массив, допуская смену состава и последовательность фаз. Методы, обрабатывающие фазы, находятся так же с помощью аннотаций, поэтому возможно создать в своем классе необходимый обработчик и пометить его (плюс к этому доступно переопределение в рамках класса). Большим плюсом стало то, что такое разделение позволило разделить тест на слои: если ошибка в готовом тесте произошла в рамках фазы package-generate или generate, значит повреждена тестовая обвязка. Если class-generate есть проблемы в конфигурационных механизмах фреймворка. Если в рамках test ошибка в тестируемом функционале. Фаза test технически может выдавать ошибки как в обвязке, так и в тестируемом функционале, поэтому возможные ошибки обвязки мы обернули в специальный тип InnerException.

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

Здесь, наверное, уже возник вопрос, а откуда берутся инстансы тестирования. Если конструктор пустой, это очевидно: с помощью Reflection API просто создается инстанс тестируемого класса. Но как в этой конструкции передавать параметры или выполнять настройку инстанса после срабатывания конструктора? Что делать, если объект строится билдером или вообще речь идет о тестировании статики? Для этого разработан механизм провайдеров, которые скрывают за собой сложность конструктора.

Параметризация по умолчанию:

@IProvideInstanceCheckBox generateCheckBox() {    return new CheckBox((MobileElement) ElementProvider.getInstance().provide("//check-box").get());}

Нет параметров нет проблем (мы тестируем класс CheckBox и регистрируем метод, который и будет создавать инстансы для нас). Поскольку здесь переопределен дефолтный провайдер, в самих тестах не потребуется добавлять ничего, они автоматически будут использовать этот метод как источник. Этот пример явно иллюстрирует логику Fast-Unit скрываем сложное и ненужное. С точки зрения теста, совершенно неважно как и откуда возьмется мобильный элемент, оборачиваемый классом CheckBox. Нам важно лишь, что существует некоторый объект CheckBox, удовлетворяющий заданным требованиям.

Автоматическая инъекция аргументов: положим у нас есть вот такой конструктор:

public Mask(String dataFormat, String fieldFormat) {    this.dataFormat = dataFormat;    this.fieldFormat = fieldFormat;}

Тогда тест этого класса с использованием инъекции аргументов будет выглядеть вот так:

Object[] dataMask={"_:2_:2_:4","_:2/_:2/_:4"};@ITestInstance(argSource = "dataMask")@Test@IExpectTestResult(errDesc = "Неверно сконвертировано значение", value = FAST_RESULT,expected = "12/10/2012")public void convert() {    runTest("convert","12102012");}

Именованные провайдеры


Наконец, если провайдеров нужно несколько, мы используем связывание с помощью имен, не только скрывая сложность конструктора, но и показывая его реальный смысл. Ту же задачу можно решить вот так:

@IProvideInstance("Дата")Mask createDataMask(){    return new Mask("_:2_:2_:4","_:2/_:2/_:4");} @ITestInstance("Дата")@Test@IExpectTestResult(errDesc = "Неверно сконвертировано значение", value = FAST_RESULT,expected = "12/10/2012")public void convert() {    runTest("convert","12102012");}

IProvideInstance и ITestInstance связанные аннотации, позволяющие указать методу, откуда брать тестируемый инстанс (для статики просто возвращается null, поскольку в конечном итоге этот инстанс используется через Reflection API). Подход с провайдерами дает гораздо больше информации о том, что на самом деле происходит в тесте, заменяя вызов конструктора с какими-то параметрами на текст, описывающий, предварительные условия, так что, если конструктор вдруг поменяется, мы должны будем лишь поправить провайдер, но тест останется неизменным, пока не поменяется реальный функционал. Если же при ревью, вы увидите несколько провайдероов, вы обратите внимание на разницу между ними, а значит и особенности поведения тестируемого метода. Даже совершенно не зная фреймворка, а лишь зная принципы работы Fast-Unit, разработчик сможет прочесть код теста и понять что делает тестируемый метод.

Выводы и итоги


У нашего подхода оказалось немало плюсов:

  • Легкая переносимость тестов.
  • Сокрытие сложности обвязок, возможность их рефакторинга без разрушения тестов.
  • Гарантия обратной совместимости изменения имен методов будут зафиксированы как ошибки.
  • Тесты превратились в достаточно подробную документацию для каждого метода.
  • Качество проверок значительно выросло.
  • Разработка юнит-тестов стала конвейерным процессом, а скорость разработки и ревью значительно выросла.
  • Стабильность разработанных тестов хотя и фреймворк, и сам Fast-Unit активно развиваются, деградации тестов не происходит

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

Текущие проблемы и планы:

  • Рефлексивные вызовы создают некоторую сложность, поскольку не работает прямое перемещение в редакторе и убиваются примитивы. Мы рассматриваем варианты замены рефлексии на интерсепторы, однако при этом потеряются проверки приватных методов (сейчас фаст-юнит игнорирует модификаторы доступа тестируемых методов).
  • Обработчики фаз на данный момент могут обрабатывать только одну фазу.
  • Обработчики фаз определяются однозначно и не могут быть переопределены.
  • На данный момент написано достаточно мало готовых компонентов, то есть сейчас инструмент является в первую очередь именно ядром юнит-тестов.
  • На данный момент Fast-Unit реализован на базе junit4, но в ближайшее время мы собираемся добавить поддержку junit5 и testng
Подробнее..

Tladianta инструмент тестирования или нечто большее

10.11.2020 18:17:06 | Автор: admin


Всем привет! Я Максим Кузнецов, и я продолжаю цикл статей рассказом об инструменте автоматизированного тестирования в Росбанке.


В прошлый раз вы читали:


  1. Fast-Unit или декларативный подход к юнит-тестам
  2. Tladianta. Сервис по автоматизированному тестированию в Росбанке

Я сегодня расскажу о самом инструменте фреймворке Tladianta.


Этот инструмент задумывался как база для легкого течения процесса тестирования в его новом виде. Менеджеры придумывают процесс и управляют им, а исполнителям нужен инструмент, а лучше семейство инструментов, которое отражает и обслуживает процесс.


Tladianta это первый базовый инструмент сервиса по автоматизированному тестированию, который наша команда предоставляет на весь банк.


Какие задачи он должен решать?


1. Легкий старт и удобство настройки

Предполагается использование фреймворка во многих командах. Много-много задач типа get started. В идеале должно быть так: создал проект и начал сразу писать тестовые сценарии.


2. Легкая поддержка и возможность обновления для всех команд

Каждая команда будет использовать определенную часть фреймворка (или несколько) и эта часть должна легко обновляться и быть всегда стабильной.


Легкость поддержки сотрудниками сервиса АТ должна быть на уровне я не сильно разбираюсь в специфике проекта вашей команды, но в том, как работает фреймворк тестирования Tladianta, я вам помогу на 100%.


3. Охват основных платформ разработки

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


  • Web (HTML, CSS, JavaScript),
  • Desktop (Delphi, C++ и прочие),
  • Mobile (Android, iOS),
  • Back-end(REST-services, MQs очереди).

Фреймворк должен позволять писать тестовые сценарии для любой из них, оставаясь при этом в процессе Tladianta


4. Простота наращивания функционала фреймворка

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


При этом изменение и доработка функционала фреймворка не должны приводить к поломке уже написанных на нем тестов в командах.


5. Возможность настройки под команду или под систему.

Вот мы пришли в команду с чемоданом счастья, прошли Get started и начали писать тесты сразу, используя функционал из коробки.


Это в идеале.


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


Все это должно работать и при этом оставлять проект с использованием нашего фреймворка на поддержке командой сервиса АТ.


6. BDD стиль в написании сценариев

Что в BDD клёво, так это человеко-читаемый и одновременно авто-исполняемый текст сценария. Важно, чтобы все члены команды могли прочитать сценарий и понять, какую часть функционала протестировали.


BDD каким он задумывался: аналитик пишет сценарий, разработчик его воплощает, а автоматизатор делает его авто-исполняемым.


В банке же реальность это различные гибридные варианты. Например:


  • ПО куплено из коробки или разработано вендором, а команде нужно контролировать основные сквозные сценарии;
  • команда разработки ПО в банке и команда тестирования это две разные команды. Ситуация немного похожа на первую, только разработка внутри банка. Так, команда тестирования создает свои e2e тесты, чтобы контролировать основные сценарии и свои доработки;
  • Legacy ПО, которое взяли на поддержку и стали покрывать тестами.

То есть это уже Behavior Driven Testing когда разработка уже давно завершена. А вот прелесть человеко-читаемого описания поведения сложно переоценить и этот подход нужно учесть наравне с классическим BDD.


Значит, фреймворк должен говорить на языке Gherkin.


7. Единая библиотека шагов сценария

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


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


То есть нам нужно иметь 80% всех необходимых шагов, чтобы можно было сразу начать писать сценарии, а оставшиеся 20% шагов добавлять под специфику проекта.


8. Возможность делиться шагами с другими командами

В банке большое число сложных IT-систем, которые переплетены между собой довольно сильно, и в случае e2e сценариев иногда бывает очень сложно обойтись без того, чтобы не проделать ряд действий (подготовительных или проверочных) в другой системе, не в той, которую тестируем сейчас.


Вот эту другую систему поддерживает другая команда, которая пишет для нее свои тесты. На нашем фреймворке. То есть все простые действия, которые нужно сделать в их системе, эта команда уже автоматизировала.


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


9. Гибкий механизм конфигурирования проекта с тестами

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


10. Одновременное использование нескольких платформенных модулей

Нужно охватить еще такой случай. Допустим, команда поддерживает и тестирует некий портал и в сценариях зачем-то нужно сходить в back-end, например, через REST проверить результат или через него же подготовить данные (вдруг с разработкой все по науке сделано :-) ).


Другими словами, тестируем Web и нужно не отходя от кассы что-то сделать в REST. За обе эти части отвечают разные модули, и нужно иметь возможность использовать их одновременно в сценарии.


11. Удобство в расследовании падений и сбора результатов

Это требование про сервис отчетности. Должно быть удобно:


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

12. Удобство e2e тестирования

Об этом было понемногу в пунктах выше, но некоторые моменты стоит выделить отдельно. BDD ориентированность фреймворка подразумевает сценарные тесты, а они бывают в основном функциональные и end-to-end.


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


Да, следует максимально делать независимые тесты, но в случае, если иначе никак, создание и прогон таких сценариев должны быть максимально безболезненными. Заглушки это благо, но не всегда они есть и часто создать их невозможно.


13. Увеличение вовлеченности автоматизаторов на местах в развитие инструмента

Фреймворк должен задавать общие правила и давать равные возможности для автотестирования многим (в идеале всем) командам. В этом случае он просто обязан быть удобным.
А значит, следующий шаг развития переход к opensource внутри банка.


14. Единая отчетность, сбор метрик и легкое формирование Dashboards

В процессе трансформации в банке образовалось много Agile-команд, которые, тем не менее, все еще работают на один результат все ПО банка должно работать слаженно, в идеале без ошибок и приносить удовлетворение клиентам.


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


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


15. Использование в Agile командах

BDD задумывался его авторами для облегчения взаимодействия в команде трех ролей:


  • аналитик/owner знает, что должно получиться;
  • разработчик знает, как сделать то, что хочет owner;
  • тестировщик знает, как проверить то, что сделает разработчик, чтобы оно работало как хочет owner.

В команде они в тесном общении создают качественный продукт.


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


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


Архитектура


Tladianta реализована на архитектуре компонентов типа "Звезда", где центральной частью является компонент "common", который предоставляет основные глобальные возможности фреймворка.


Плагины предоставляют функционал и реализацию шагов для конкретного стека технологий (платформы), на которых написано тестируемое приложение.


Плагинов в семействе компонентов фреймворка пока 4:


  • HTML-plugin для тестирования веб-приложений, сайтов, порталов и пр. на различных браузерах;
  • Desktop-plugin для тестирования desktop-приложений, написанных на Swing, AWT, .Net и пр. языках высокого уровня, Windows-приложения, а также терминальные. Например, Bank Information System;
  • Mobile-plugin для тестирования мобильных приложений на iOS/Android;
  • Rest-plugin для тестирования REST API приложений любых типов.

Ассортимент и функционал плагинов может (и будет) расширяться. Плагин должен отвечать небольшим требованиям, чтобы иметь возможность работать под управлением "common".


Так, у каждого модуля есть своя команда разработки, которые работают почти независимо.


Какие задачи решает:


  • охват основных платформ разработки;
  • простота наращивания функционала фреймворка;
  • одновременное использование нескольких платформенных модулей;

Конфигурирование


Запуск тестов на выполнение, как правило, конфигурируется различными свойствами. Эти свойства имеют различные области (уровни) влияния.
Так, например, можно выделить:



Кроме того, часто нужно задать значения свойств любого уровня специально для среды запуска: DEV, TEST, CERT, а также опционально добавлять к набору свойств конфигурации группу свойств под конкретный тест или группу тестов (настройки подключения к базе данных, стороннему сервису и прочие).


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


По умолчанию конфигурация собирается следующим образом:



Загрузка свойств происходит по принципу "каждый следующий затирает предыдущего". Перезапись значения свойства происходит по имени свойства.
Такой подход дает возможность переопределять свойства уровня фреймворка и/или, плагина в проекте, в свойствах среды и т.д.


Какие задачи решает:


  • легкий старт и удобство настройки;
  • Возможность настройки под команду или под систему;
  • гибкий механизм конфигурирования проекта с тестами;

Контекст исполнения сценария


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


В Tladianta реализован механизм регистрации действий для установки контекста проекта. Это такой список отложенных действий, который есть у плагина и у проекта.


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


Такой подход позволил заложить удобство при переходе на контекст другого проекта и использование его шагов прямо в том же самом сценарии (см. далее).


Какие задачи решает:


  • возможность делиться шагами с другими командами;
  • удобство e2e тестирования.

Гостевой модуль использование шагов и контекста других проектов.


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


В своих проектах команды реализуют тестовое взаимодействие со своим тестируемым приложением клики, заполнение полей, проверки и т.д.


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


Я прекрасно понимаю гнев и негодование BDD-евангелистов, но что есть, то есть.


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


Для реализации такой возможности Tladianta имеет спец шаги переключения контекста.

Вот тут и пригодились те самые отложенные действия.


Сценарий при этом может выглядеть так:



Каждый проект на базе Tladianta должен иметь свойство конфигурации app.name с понятным человеку именем. Это имя идентифицирует контекст проекта и используется для переключений/установки контекста в сценарии.


В момент переключения контекста сценария будут выполнены все [отложенные] действия установки контекста, зарегистрированные для конкретного проекта.


Чтобы любой проект на базе Tladianta можно было использовать как гостевой в других проектах, он должен отвечать ряду требований:


  1. проект тестирования должен быть построен на базе Tladianta-framework;
  2. проект тестирования должен собираться по релизам и публиковаться в банковский репозиторий nexus;
  3. проект подключается как гостевой через зависимость в POM-файле принимающего проекта. Последний стабильный релиз;
  4. проект тестирования в процессе сборки релиза должен включать ресурсы с файлами свойств конфигурации.

Таким образом, все проекты тестирования объединяются в единую экосистему тестирования, подчиненную общим правилам, что значительно упрощает их поддержку силами отдела сервиса АТ, одновременно сохраняя индивидуальность каждой команды.


Какие проблемы решает:


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

Библиотека шагов.


Tladianta реализует принцип "Создай шаг один раз и переопределяй его метод, где нужно".
Шаги, составляющие библиотеку, разбиты на несколько уровней:


  • общие шаги для всех проектов на базе любых плагинов;
  • шаги плагина;
  • шаги проекта.

Вместо классической реализации шагов cucumber Tladianta разделяет определение шага (step definition) и реализацию шага (step implementation) на две разные сущности.
Это позволило отделить формулировки шага и собрать их в библиотеку, оставив плагинам и проектам работу над реализацией конкретного поведения шага.


Таким образом, одна формулировка шага может иметь разную реализацию в разных плагинах и проектах.


Создавая сценарий, больше не нужно беспокоиться о том, что шаг "занят" в другом плагине и нужно дублировать его у себя, меняя формулировку или вставляя разные костыли в виде символов точек, лишних пробелов и так далее, чтобы избежать ошибки "Multiple step definition found".


Вместо этого нужно просто переопределить метод этого шага в своем проекте или даже на конкретной странице.


Внешнее поведение шага, интуитивно ожидаемое от его формулировки, останется тем же, скрывая под капотом нюансы его реализации в каждом конкретном случае.


Мы постарались собрать в библиотеку те самые 80% шагов, которые позволят сразу из коробки написать сценарий средней сложности.


Роль сервиса АТ также позволяет нам вылавливать из оставшихся 20% шагов, которые команды делают себе сами, те шаги, которые объективно нужны многим, и мы добавляем их в библиотеку фреймворка. Автоматизаторы в командах, таким образом, принимают участие в развитии инструмента.


Какие задачи решает:


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

Тестовые данные и шаблоны генерации значений параметров шагов


Cucumber дает возможность часть текста шага использовать как параметр. Это очень удобно.
Tladianta расширяет эту возможность динамической параметризацией шагов.


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


Tladianta перед выполнением сценария все шаблоны заменит на конкретные значения из тестовых данных и в отчетах о прогоне вы увидите уже их.


В качестве источников тестовых данных могут использоваться:


  • Json
  • Excel
  • Properties
  • Mongo DB

Генераторы значений


Не все тестовые данные можно спрогнозировать заранее и завести их в файлы. Некоторые значения имеют смысл прямо в моменте исполнения теста, например, текущая дата, случайное число и т.д.


Tladianta представляет очень удобный механизм генерации текстовых значений "на лету" это генераторы значений.


Работают они так же, как и шаблоны авто-замены тестовых данных, но имеют немного другой синтаксис и время срабатывания.
Генераторы значений отрабатывают уже после подстановки тестовых данных.


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


Какие проблемы решает:


  • возможность настройки под команду или под систему;
  • BDD стиль в написании сценариев.

Древовидная структура


Продолжаем тему длинных сквозных сценариев.
Тут есть дилемма атомарные шаги или читаемый сценарий.


Правильно это и то, и другое.


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


Обычно такие сценарии подлежат рефакторингу разбивке на части и упрощению. Беда в том, что после разбивки, такие части сами по себе теряют смысл.


Например, у нас есть сценарии из 700+ шагов. Это большие такие сквозные сценарии. В функциональных тестах отдельные части протестированы. А в этом e2e сценарии ничего не выкинуть. Только читать и поддерживать его невозможно. Что делать?


Мы сделали сценарий древовидным.


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


Например,



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



Вы заметили, что это уже не cucumber шаги?


Это то, что понимает, скажем, аналитик, который знает назубок этот сквозной сценарий. Если сценарий упадет, он довольно быстро сможет понять, в каком месте сломалось. Ему не нужно быть для этого автоматизатором. Ему достаточно уметь открыть отчет Allure и знать русский язык.


Древовидное отображение сценария мы сделали в среде разработки и в отчете Allure.


Узлы дерева можно сворачивать и читать сценарий по верхам.


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


Какие задачи решает:


  • BDD стиль в написании сценариев;
  • удобство в расследовании падений и сбора результатов;
  • удобство e2e тестирования.
  • использование в Agile-командах

Page Object


Мы выбрали шаблон PageObject для архитектуры автотеста как основной, но не единственный. Просто он объектно-ориентированный, это так по javaвски.


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


Вкратце PageObject предполагает описание формы или экрана приложения как отдельного java-класса, а поля класса это части интерфейса формы: поля ввода, кнопки, флажки, таблицы и прочее.


В сценарии специальным шагом

объект страницы устанавливается как текущий и дальнейшие шаги работают в контексте этой страницы.


Блоки.


Страницы бывают сложные: много вкладок, разных сгруппированных полей и часто у этих полей одинаковые относительные пути (xPath), что наводит на мысль о DRY, переиспользовании, ООП в конце концов.


Логично выделить их в отдельную сущность и вообще разбить страницу на группы, области.


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


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


Например, на странице есть два повторяющихся элемента: "Номер" и "Остаток". Они присутствуют на странице в двух местах: "Данные счета" и "Данные карты".
В этом случае элементы "Номер" и "Остаток" нужно вынести в отдельный класс-блок, а на страницу добавляем два элемента-блока "Данные счета" и "Данные карты".
В шаге обратиться к элементу "Остаток" для разных блоков можно следующим образом:



Блоки элементов могут быть вложены друг в друга



Блоки могут быть списками



Такая навигация очень помогает ориентироваться в сценарии и приложении.


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


Довольно удобно.


Какие задачи решает:


  • BDD стиль в написании сценариев.
  • удобство в расследовании падений и сбора результатов.
  • использование в Agile командах всем просто понять сценарий

Использование нескольких плагинов в одном проекте


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


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


Самая распространенная ситуация это когда нужно результат действий через UI проверить через REST запросы к бэкенду приложения.


Какие задачи решает:


  • одновременное использование нескольких платформенных модулей;

Запись видео.


Tladianta представляет конфигурируемый и настроенный "из коробки" инструмент записи видео по умолчанию, который, однако, можно переопределить или добавить свой у себя в проекте.


Перед запуском теста фреймворк запускает все зарегистрированные видео-рекордеры и по окончании сценария останавливает их.


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


Какие задачи решает:


  • возможность настройки под команду или под систему.
  • гибкий механизм конфигурирования проекта с тестами.
  • удобство в расследовании падений.

Allure-report


По-умолчанию результаты прогона тестов логируются в Allure-отчет. Логирование поддерживает древовидную структуру сценария, если она используется. В отчет попадают также логи, сделанные с помощью Sl4j.


Allure позволяет группировать сценарии по Epic/Feature/Story/Case. Это полезно, если у вас есть (должны быть) тестовая модель и матрица зависимости. И когда просматриваешь отчет, который сгруппирован так, как у вас модель тестовая составлена, то становится очень удобно, т.к. по упавшему тесту в отчете сразу видно, какой связанный функционал пострадал и потенциально стал нерабочим.


Требование к наличию модели и матрицы зависимости в сочетании с отчетами в Allure позволяют создавать базу для внедрения различных методик расчета метрик, т.к. все команды выгружают такие результаты.


Все результаты собираются в одном месте по проектам/командам и вместе дают ту самую целую картину здоровья ИТ-ландшафта. Причем, собираются также результаты тестов, которые написаны не на Tladianta.


Это уже не фреймворк Tladianta (он только генерирует данные), это уже процесс Tladianta.


Какие задачи решает:


  • BDD стиль в написании сценариев.
  • удобство в расследовании падений.
  • единая отчетность, сбор метрик и легкое формирование Dashboards.
  • Использование в Agile командах

Передача данных между шагами и сценариями.


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


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


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


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


Кроме того, данный контекст можно закрепить за конкретным сценарием и сохранить его в базе данных. Опционально. Для этого есть отдельные методы, их можно использовать в Before/After-хуках в проекте.


По-умолчанию контекст сценария очищается перед каждым сценарием и не сохраняется в базу данных.


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


Какие задачи решает:


  • удобство e2e тестирования;

Шаблонные проекты.


Это часть семейства инструментов Tladianta.


Мы сделали заготовки, шаблоны проектов, которые настроены на работу с каким-то одним плагином. Сделали в них структуру со всеми ключевыми пакетами и классами. Сделали настройку для фичи гостевой проект, для выгрузки отчета Allure.


Просто делай клон, пиши имя проекта и начинай писать тесты.


В проектах можно кастомизировать почти все, что может фреймворк:


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

Какие задачи решает:


  • легкий старт и удобство настройки;
  • охват основных платформ разработки;
  • возможность настройки под команду или под систему;

Интеграция с внешними сервисами и инструментами.


Фреймворк позволяет подключать к нему различные интеграторы/выгружаторы результатов выполнения теста.


Мы сделали репортер в ALM и репортер в Jira.


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


Tladianta-editor


Это плагин для среды разработки IntelliJ IDEA.


Его основное назначение повысить скорость и комфорт в разработке сценария.


Можно создать рабочий сценарий не выходя из файла .feature, при условии что использован шаблонный проект, конечно.
Он позволяет:


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

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


Реализацию нового шага или специфичную реализацию существующего шага придется все-таки писать самостоятельно. Но для этого есть автоматизатор :-)


Заключение


Как видите, мы нарушили много канонических положений BDD. При этом мы сделали cucumber пригодным для использования в наших банковских реалиях. Получился такой cucumber по-росбанковски. Поэтому и Tladianta.



Не все идеи мы придумали сами. Многие из них мы почерпнули из трудов таких замечательных ребят как Константин Мальцев, Виктор Сидоченко, Алексей Лустин, Артем Ерошенко и других авторов open-source проектов.


Работа над фреймворком Tladianta не завершена. Мы его полируем и дополняем. Некоторые фичи еще не реализованы, о них, как и о представленных в статье, более подробно я расскажу в следующих статьях.

Подробнее..

Как мы реализовали параллельный запуск Cucumber-сценариев на разных хостах

11.02.2021 22:07:58 | Автор: admin

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

Наш тестовый фреймворк реализован на базе Cucumber (Java). Основной фокус автоматизация GUI тестирования Swing-приложений (используем AssertJ Swing), а также взаимодействие с БД (SQL), REST API (RestAssured) и web UI (Selenide).

Ситуация осложнялась тем, что подключить параллелизацию стандартными средствами (например, настройкой потоков в maven-surefire-plugin) мы не могли, так как специфика тестируемых приложений не позволяет запускать более одного экземпляра приложения на одном физическом хосте.

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

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

Обзор реализации

Для нашей задачи мы решили использовать паттерн master-worker с коммуникацией посредством очереди сообщений.

Компоненты схемы:

  • Master-хост, на котором запускается модуль Dispatcher, управляющий созданием очереди сценариев для параллельного запуска и последующей агрегацией результатов.

  • JMS server (для простоты развертывания мы поднимаем свой ActiveMQ Artemis, встроенный в Dispatcher).

  • Горизонтально масштабируемые agent-хосты, на которых запускается FeatureExecutor, непосредственно выполняющий сценарии из очереди. На каждый agent предварительно должен быть установлен тест фреймворк.

Master-хост при этом может одновременно выполнять роль одного из агентов (для этого запускаем на нем и Dispatcher, и FeatureExecutor).

Dispatcher при старте получает на вход директорию с features, считывает список файлов, и отправляет их в JMS очередь сценариев.

FeatureExecutor считывает сценарий из очереди и отправляет команду в Test Framework на выполнение этого сценария.

Как получить общий отчет по результатам прогона со всех хостов?

Как мы знаем, Allure складывает файлы с результатами по каждому сценарию в директорию resultsDir (по умолчанию это build/allure-results).

Так как мы уже используем JMS для создания очереди сценариев, закономерным решением мы посчитали добавление еще одной очереди для передачи результатов.

FeatureExecutor после каждого сценария архивирует содержимое resultsDir и в виде BytesMessage отправляет в эту очередь, откуда их считывает Dispatcher и распаковывает в resultsDir уже на мастер-хосте.

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

Что, если один из агентов упал?

Диспетчер завершает работу, когда обработал все результаты (сравниваем поштучно количество отправленных сценариев VS количество полученных результатов). Если один из агентов забрал сценарий из очереди, но не отправил результат, можно получить зависший прогон, так как диспетчер будет бесконечно ждать этот результат

Для решения этой проблемы мы добавили в Dispatcher сервис HealthChecker, который в фоновом потоке через RMI-интерфейс по шедулеру вызывает метод isAlive() на каждом зарегистрированном агенте (список агентов мы загружаем из конфигурации на старте).

Реализация метода на агенте примитивна:

@Overridepublic boolean isAlive() {return true;}

Если связь хотя бы с одним агентом была потеряна, прогон завершается.

Такое условие было реализовано по принципу минимальных вложений в первой версии нашего механизма.

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

Альтернативные опции:

  1. По аналогии с RMI использовать REST API.

  2. Создать отдельную JMS очередь для сообщений типа heartbeat, которые будут отправлять агенты. А на стороне Dispatcher проверять, что от каждого агента мы получаем минимум один heartbeat в 5-10-30 минут (конфигурация по вкусу).

Как быть с тестами, которые не могут выполняться параллельно?

Например, использующие общие ресурсы.

Наше решение стилизовано под специальный Cucumber тег в feature-файле @NoParallel. Почему стилизовано? Потому что читаем мы этот тег средствами java.nio.file, а не через Cucumber. Зато он красиво вписывается в файл сценария:

@NoParallel(PrimaryLicense)@TestCaseId("876123")Scenario: 001 Use of shared resource

Если два сценария используют общий ресурс (обозначенный в теге @NoParallel) они не должны запускаться параллельно.

Для управления ресурсами у нас реализован ResourceManager на стороне Dispatcher с двумя методами в API:

public boolean registerResource(String resource, String agent);public void unregisterResource(String resource, String agent);

Когда FeatureExecutor получает сценарий из очереди с тегом @NoParallel, он вызывает метод registerResource().

Если метод возвращает true ресурс успешно зарегистрирован, продолжаем выполнение сценария.

Если получаем false ресурс занят. Сценарий возвращается в очередь.

После выполнения сценария ресурс освобождается через unregisterResource().

Взаимодействие с ResourceManager у нас реализовано через RMI.

Как вариант, можно использовать REST API.

Summary

  1. Данное решение стоило нам 0 изменений в тестовом фреймворке.

  2. Как следствие имеем полную обратную совместимость. Автотесты могут запускаться и старым, и новым способом без изменений в коде.

  3. Не нужно заботится о потокобезопасности тестов. Они изолированы, поэтому нет разницы, запускаются они параллельно или нет.

  4. Агенты горизонтально масштабируются, легко ускорить выполнение тестов до определенного предела.

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

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru