UI тести: Cucumber + Selenide

Частина 1
Сьогодні поговоримо про створення UI smoke-тесту для сайту з використанням фреймворків Cucumber і Selenide. Стаття розрахована на junior, який зовсім нічого не знає про дані фреймворки. Досвідчений junior знайде у другий частини цікаві моменти, до яких я доходив пару місяців.
Стаття складається з двох частин:
  • у першій описано створення нашого тесту найпростішим способом – щоб використовувалася і при цьому ніяких складних речей з фреймворків не використовувалося. Тільки створимо опис фічі (.feature файл) і клас опису степов з використанням Selenide.
  • другий частини у той самий тест додамо всякі цікаві штуки від Selenide, подивимося, як створювати красиві звіти, які будуть містити текст фіч (мн.ч від слова «фіча»).
Фреймворки
Selenide – фреймворк (а точніше бібліотека), огортаючий Selenium. Чим він відрізняється, прекрасно описано автором, Андрієм Солнцевым. Головна відмінність – Selenide дозволяє скоротити купу рядків коду при написанні UI тестів, що є однією з головних завдань при створенні тестів/написанні коду, бо Ви повинні піклуватися про те тестері, який прийде після Вас і повинен буде розбирати Ваше творіння.
Cucumber – це фреймворк, що реалізує підхід BDD/TDD.

Я не претендую на глибоке теоретичне знання BDD/TDD, поки що для мене вони суть одне і теж.

BDD/TDD з практичної точки зору:

  1. Від бізнесу приходить тех. завдання, на підставі якого програмісти повинні запив нову функціональність – створити фічу
  2. Перш ніж програмісти почнуть писати код (як це робиться в більшості випадків), і тестери і програмісти сідають за круглий стіл і обговорюють – як саме фіча буде працювати. Результатом круглого столу є записана на папері фіча – набір дій клієнта/користувача, яка приводить до певного результату: а) натиснув сюди; б) ввів цифри туди; в) отримав результат там
    В результаті такого круглого столу створюється одне розуміння на всіх даної фічі, задокументований на папері
  3. Далі програмісти починають писати код, згідно описаної фічі. Тестери також починають паралельно писати тести, бо записана фіча, завдяки Cucumber, є майбутнім тестом. Зрозуміло, що тест може бути завершено тільки після того, як закінчать кодити програмісти, але таким чином написання коду і тестів йде паралельно, що прискорює процес розробки
Ще плюси Cucumber:
  • непотрібність логування при написанні тестів – кожен степ (дія користувача) по суті своїй є логированием.
  • людино-ясна опис тестів – тести будуть зрозумілі навіть людям з бізнесу, що може стати в нагоді при демонструванні звітів про тестування.
  • при описі бага не потрібно придумувати steps to reproduce – необхідні стьопи беруться зі звіту копіпастом
Проект на гітхабі
Відео виконання тесту на youtube


Розберемо першу, просту частина simple_selenide_cucumber.

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



Використовуємо Intellij IDEA, Maven і Junit.
mail.txt записані логіни, паролі облікових записів для роботи з тестом. УВАГА: якщо будете запускати у себе, майте на увазі, що система викине одного з юзерів, які будуть логінитися під одним логіном/паролем. Поміняйте мейл
pom.xml прописуємо наступні dependency:
<dependencies>

<dependency>
<groupId>com.codeborne</groupId>
<artifactId>selenide</artifactId>
<version>3.5</version>
</dependency>

<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-java8</artifactId>
<version>1.2.3</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>

</dependencies>

Файл smoketest#1.feature є тією самою фичей (описом фічі), яку погодили програмісти і тестери за круглим столом (в ідеальному світі:). Як бачимо, це опис дій користувача на сайті, записані в людино-зрозумілій формі, тобто це ще й ваш файл логування за умови, що кожен степ(дія) не передбачає дуже складної логіки:
Feature: smoke test #1, go through the service to Yandex-pay-page

Scenario: go through the service to button "Придбати"

#actions at first page
Given open riskmarket.ru
When press button with text "Вхід в кабінет"
And type to input with name "userName" text: "riskmarket.testoviy2016@yandex.ru"
And type to input with name "password" text: "l0dcfJMB"
And press element with value "Увійти"
...
Scenario: go through service to yandex pay-page

Given press button with text "ПРИДБАТИ"
#actions at third page
When type to input with name "lastName" text: "TESTOVIY"
...

Створення вашого UI тіста починається саме з цього файлу, файл з розширенням .feature. Ви повинні помістити його в пакет
test/java/.../features/

Фіча повинна починатися з ключового слова:
Feature:

Тут вказується загальними словами що саме робить фіча. У нашому випадку smoke-тесту «Пройти через сервіс до сторінки Яндекс.платежів»
Далі йде ключове слово:
Scenario:

Сценарій фактично є окремим тестом, тобто фіча може містити скільки завгодно сценаріїв (тестів). Всі сценарії, очевидно, повинні ставитися до цієї фиче. В нашому випадку буде два сценарії, перший – пройти до кнопки «Купити» і другий – пройти до сторінки платежів. За правилами тестування, сценарії (тести) повинні бути незалежними, тобто успіх проходження одного сценарію не повинен залежати від успіху проходження другого сценарію. УВАГА: в нашому випадку це не виконується – другий сценарій починається на місці зупинки першого сценарію, і якщо перший звалиться, то другий теж.
У сценарію також є короткий опис – що саме він робить.
Далі йдуть самі стьопи. Перед кожним степом повинно бути одне з ключових слів
Given, When, Then, And
або
But
.
Given
— позначає початкові умови, Дано: те-то і те-то»
When
– дії користувача: натиснути сюди, почекати
Then
– результат, який виходить: найчастіше це якась перевірка, як у нашому випадку
Then element with tag "search-result-item" should exist

та
Then verify that page with url "http://money.yandex.ru/cashdesk" is opened

And
,
But
– використовується як союз «і», «та», щоб легше читалося. З «і» — все ясно. «та» може використовуватися, наприклад, в степах, що описують думка «… ця штука повинна бути видна, АЛЕ ось ця повинна бути прихована»
Намагайтеся дотримуватися поділ степов на зазначені три частини (
Given, When, Then
), т. к. це правила BDD/TDD.
Після написання фічі ви можете запустити тест (правою клавішею по файлу фічі -> Run). Результатом буде багато
Undefined step: <текст стьопа>
. Система натякає, що вона не знає як виконати кожен степ. Потрібно підсунути логіку виконання стьопа. Якщо ви пишете в ІДЕЇ, то у вас кожен невизначений степ підсвічений. Натисніть Alt+Enter і пройдіть по всім діалогових вікон, не змінюючи значень. Буде створено клас
MyStepdefs
(я для зручності помістив його в пакет
steps
). Ви побачите щось типу:
@Given("^open riskmarket\\.ru$")
public void openRiskmarketRu() throws Throwable
{
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
}

За замовчуванням методи, що визначають стьопи кидають
PendingException()
. Це потрібно, щоб не було невизначених степов, і щоб при цьому можна було продовжувати писати тести. Тобто поки фіча пишеться програмістами, деякі стьопи вже можна визначити, а деякі повинні дочекатися написання коду програмістами. Кожен раз при запуску тесту система буде нагадувати вам, які саме стьопи ще не визначені.
Ви також можете використовувати лямбда-вирази для опису степов. Але я не буду розбирати це тут, т. к. це окрема тема. Будемо робити по-старому.
Розберемо визначення стьопа докладніше:
@Given("^open riskmarket\\.ru$")
public void openRiskmarketRu()

Перший рядок – це анотація, з допомогою якої Cucumber розуміє до якого саме степу відноситься дане визначення. На місці
@Given
, як говорилося раніше, може стояти
@And/@Then/@But/@When
. Далі в аргументі анотації використовується регулярний вираз(regex).
Regex – це тема окремої статті, почитайте де-небудь, матеріалу повно.
Наведу ключові використовувані символи regex, які потрібні для старту:
  • ^ — початок рядка
  • $ — кінець рядка
  • (.*) – якою завгодно текст
  • "([^"]*)" – будь-який текст, але в лапках
Наступна рядок
public void openRiskmarketRu()
це назва методу. Метод, що визначає степ, завжди повинен бути
public void
. Якщо ви використовуєте Alt+Enter, то ІДЕЯ сама синтезує назва методу, найчастіше цього досить.

Розберемо деякі стьопи.

В описі логіки степов використовується Selenide
  1. Вигляд у фиче:
    Given open riskmarket.ru

    Вигляд у MyStepdefs:
    @Given("^open riskmarket\\.ru$")
    public void openRiskmarketRu()
    {
    open("http://riskmarket.ru");
    }

    Завдяки методом
    open(...)
    Selenide в одній сходинці створюється instance WebDriver (за замовчуванням Firefox) і відбувається перехід на вказаний url. Закривати/вбивати instance не потрібно, це зробить Selenide
  2. Вигляд у фиче:
    When press button with text "Вхід в кабінет"`
    And press button with text "Розрахувати поліс"
    Given press button with text "ПРИДБАТИ"
    And press button with text "Оплатити"

    Вигляд у MyStepdefs:
    @When("^press button with text \"([^\"]*)\"$")
    public void press(String button) 
    {
    $(byText(button)).waitUntil(Condition.visible, 15000).click();
    }

    Перед вами приклад перевикористання стьопа. Намагайтеся переиспользовать стьопи як можна частіше, не плодіть код. В нашому прикладі в аргументі анотації вказуємо, що «кнопка може містити будь-який текст, але в лапках». Що прикольно, можна використовувати будь-яку мову.
    Взагалі кажучи, для опису степов також можна використовувати будь-яку мову – можна писати так:
    And натиснути кнопку з текстом "Оплатити"

    Раз назву кнопки – це аргумент, то вказуємо його в сигнатурі методу:
    public void press(String button)

    $()
    – це метод Selenide для пошуку елемента на сторінці. У нього є багато різних, зручних параметрів. В даному випадку шукаємо елемент, який містить наш текст. Пишу статтю з місця з не дуже швидким інтернетом, тому потрібно додати збільшене очікування, поки елемент не з'явиться, т. к. вбудованого таймауту на 4с не вистачає.
    $(byText(button)
    дає нам єкт типу
    SelenideElement
    , у якого серед інших методів є таке очікування –
    waitUntil(Condition, timeout)
    .
    Condition
    – умова, яку ми чекаємо.
    Condition
    – це клас Selenide, в якому описано багато різних умов, подивіться, згодиться.
    І в кінці, коли ми дочекалися появи елемента, клікаєм по ньому.
    До речі, те, що тут описано в один рядок, в чистому Selenium у вас зайняло б кілька рядків коду, з створенням WebDriverWait.
  3. Вигляд у фиче:
    And type to input with name "userName" text: "riskmarket.testoviy2016@yandex.ru"
    And type to input with name "password" text: "l0dcfJMB"
    When type to input with name "lastName" text: "TESTOVIY"
    And type to input with name "firstName" text: "TEST"

    Вигляд у MyStepdefs:
    @And("^type to input with name \"([^\"]*)\" text: \"([^\"]*)\"$")
    public void typeToInputWithNameText(input String, String text)
    { 
    sleep(1000);
    $(byName(input)).sendKeys(text);
    }

    Даний степ використовується в один з разів після появи кадру, тому потрібно зробити паузу, щоб input встиг з'явиться – робиться за допомогою Selenide
    sleep(timeout with ms)
    .
    sendKeys(String)
    — отрпавляет текст в елемент.
  4. Вигляд у фиче:
    And select countries: Шенген, Фінляндія, Китай

    Вигляд у MyStepdefs:
    @And("^select countries: (.*)$")
    public void selectCountries(List<String> countries)
    {
    for (String str : countries)
    {
    $("#countryInput").sendKeys(str);
    $("#countryInput").pressEnter();
    }
    }

    При описі степов як параметр можна приймати списки – елементи перераховуються через кому.
    Інші стьопи схожі на описані вище.
    pom.xml у цей проект був доданий Junit тільки з-за останнього степу, де перевірка, що відкрився потрібний url, відбувається з допомогою assertThat().
На цьому перша частина закінчується. Читайте у другий частини про автоматичні скріншоти, кастомні
Condition
, PageObject, анотацію елементів і створення красивих звітів.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.