- PVSM.RU - https://www.pvsm.ru -
Сегодня поговорим о создании UI smoke-теста для сайта с использованием фреймворков Cucumber и Selenide. Статья рассчитана на junior, который совсем ничего не знает про данные фреймворки. Опытный junior найдет во второй части интересные моменты, до которых я доходил пару месяцев.
Статья состоит из двух частей:
Selenide [1] – фреймворк (а точнее библиотека), обертывающий Selenium. Чем он отличается, прекрасно описано автором [2], Андреем Солнцевым. Главное отличие – Selenide позволяет сократить кучу строчек кода при написании UI тестов, что является одной из главных задач при создании тестов/написании кода, ибо Вы должны заботиться о том тестере, который придет после Вас и должен будет разбирать Ваше творение.
Cucumber [3] – это фреймворк, реализующий подход BDD/TDD. Я не претендую на глубокое теоретическое знание BDD/TDD, пока что для меня они суть одно и тоже.
Прежде чем программисты начнут писать код (как это делается в большинстве случаев), и тестеры и программисты садятся за круглый стол и обсуждают – как именно фича будет работать. Результатом круглого стола является записанная на бумаге фича – набор действий клиента/пользователя, который приводит к некому результату: а) нажал сюда; б) ввел цифры туда; в) получил результат там
В результате такого круглого стола создается одно понимание на всех данной фичи, задокументированное на бумаге
Еще плюсы Cucumber:
Видео исполнения теста на youtube [5]
Используем Intellij IDEA, Maven и Junit.
В mail.txt [6] записаны логины, пароли аккаунтов для работы с тестом. ВНИМАНИЕ: если будете запускать у себя, имейте ввиду, что система выкинет одного из юзеров, которые будут логиниться под одним логином/паролем. Поменяйте мейл
В 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 [7] является той самой фичей (описанием фичи), которую согласовали программисты и тестеры за круглым столом (в идеальном мире:). Как видим, это описание действий пользователя на сайте, записанные в человеко-понятной форме, т.е. это еще и ваш файл логирования при условии, что каждый степ(действие) не подразумевает очень сложной логики:
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
Вид в фиче: Given open riskmarket.ru
Вид в MyStepdefs:
@Given("^open riskmarket\.ru$")
public void openRiskmarketRu()
{
open("http://riskmarket.ru");
}
Благодаря методу open(…)
от Selenide в одной строчке создается instance WebDriver (по умолчанию Firefox) и происходит переход на указанный url. Закрывать/убивать instance не нужно, это сделает Selenide
Вид в фиче:
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.
Вид в фиче:
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(String input, String text)
{
sleep(1000);
$(byName(input)).sendKeys(text);
}
Данный степ используется в один из разов после появления фрейма, поэтому нужно сделать паузу, чтобы input успел появится – делается с помощью Selenide sleep(timeout with ms)
.
sendKeys(String)
— отрпавляет текст в элемент.
Вид в фиче:
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, аннотацию элементов и создание красивых отчетов.
Автор: vasidzius
Источник [8]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/tdd/120386
Ссылки в тексте:
[1] Selenide: http://ru.selenide.org/
[2] прекрасно описано автором: http://github.com/codeborne/selenide/wiki/Selenide-vs-Selenium
[3] Cucumber: https://cucumber.io
[4] Проект на гитхабе: http://www.github.com/vasidzius/RiskMarket
[5] Видео исполнения теста на youtube: https://youtu.be/sA_9UYIVHf4
[6] mail.txt: https://github.com/vasidzius/RiskMarket/blob/master/simple_selenide_cucumber/mail.txt
[7] smoketest#1.feature: https://github.com/vasidzius/RiskMarket/blob/master/simple_selenide_cucumber/src/test/java/ru/riskmarket/features/smoketest%231.feature
[8] Источник: https://habrahabr.ru/post/283384/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox
Нажмите здесь для печати.