Золотой Selenide. Мои лучшие практики по тестированию

Golden selenide. My best testing practices

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

Тестирование для меня как целая наука, имеющая множество направлений.

Что такое тест?

Тест — это проверка сценария, expected === actual result.

Какие тесты бывают?

  • Unit тесты (их пишут разработчики)

  • UI тесты (их пишу я, и мы остановимся на этом)

Кратко про пирамиду тестирования. Больше всего должно быть юнит тестов, они прогоняются гораздо быстрее UI тестов, помогая разработчикам быстрее обнаружить баги в коде. Работайте по принципу один тест тестирует что-то одно. Между ними кроятся API (or service) тесты.

Мне-тебе не по душе. Какой ЯП выбрать для авто тестов?

Есть три популярнейших ЯП упрощающих жизнь автоматизаторам своими фреймворками и широким комьюнити,

  • Python (Selenium, Unittest/Pytest),

  • Java (Selenide, TestNG/JUnit),

  • C# (тут я не знаю что нужно для .NET-щиков)

Да, еще можно писать на чистом js. Хотя считаю это прошлым веком, но понимать его особо необходимо. На конференции QA от Kolesa Group узнала, что там используют PHP: D

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

Как я разделяю типы UI тестов

  • Пользовательские сценарии (шаги в системе, приводящие к определенному результату)

  • Сочетания настроек (уместно применить — техники тест дизайна)

Тестировщик, программист или аналитик, вопрос, кто живет в доме? — я скажу тестировщик — любому автоматизатору придется там жить, и далее наша речь пойдет о локаторах…

DOM — document object model. Древовидная иерархия тегов, расположения веб элементов на странице

Что такое веб элемент?

Это все блоки, точки, кнопки, div-ки из которых состоит веб страница. Все что имеет визуально-функциональный блок. Все это WEB ELEMENT-ы. Других названий не поощряю.

Распределение локаторов. Локатор — адрес/путь веб элемента на странице

  • храните в отдельном файле, так и назовите, Локаторы

  • для каждой страницы отдельный файл с локаторами — забудьте про это. Вам запарится разделять локаторы по страницам, веб элементы состоят из идентичных форм, css классов, и один локатор часто будет повторяться на разных страницах приложения. Думаете что файл взорвется? Нет, благо в современном мире есть мощные IDE, упрощающих поиск. Около 500 локаторов достаточно покрывают многие потребности по достаточно крупному проекту

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

.top-header  # Какой то класс
div.top-header  # Блок, но таких блоков может быть много
input.top-header  # Ага, поле ввода
div.top-header.logo  # Ага, сразу понятно, логотип на вверхем хэдере

Длинный локатор не проблема, когда они вынесены в отдельный файл с локаторами:

// ElementLocators.java

public class ElementLocators {

  // Это локатор, считайте как константа, хранящая в себе путь к веб-элемнету
  public static final String HEADER = "div.top-header-block";
  
  // Это не локатор, а цвет, можно объявить в этом же файле 
  public static final String RED_COLOR = "rgba(248, 248, 248, 1)";
  ...
}

Дальше я кратко напишу что еще умеет Selenide.

Complex сonditions. Selenide очень удобен написанием однострочников, которые на голом Selenium загромождают тестовый код.

$(HEADER).shouldBe(exist, enabled, visible)
  .shouldHave(attribute("title", "myTitle"), text("TEXT"));
/*
Состояния:
enabled - активный, в основном применяю для проверки кликабельных элементов
visible - элемент виден на странице
exist - элемент сущетсвует в DOM-е
*/

Разница между should, shouldBe, shouldHave — абсолютно никакой. Используйте для визуально приятного восприятия (читабельности)

Поиск из множества элементов по тексту.

  • findBy() вернет один веб элемент, а точнее SelenideElement . Все что после $(SOME_LOCATOR)вернет веб элемент селенида.

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

$$(SOME_DIV).findBy(matchText("Это заголовок div-ки"))
            .shouldBe(enabled).click();

Работа с коллекциями и их фильтрация.

// Коллекция элементов, не входящих в заданный класс:
ElementsCollection notCheckedCheckboxes = 
   $$("div.checkboxes").filterBy(not(cssClass("checked")));

Палитра на любой вкус. Проверка веб элемента по его цвету. Селенид краток, лаконичен и удобен, проверка наличия атрибута или сss класса? — не беда

$$(DANGER_BTN).shouldHave(size(1)).first()
  .shouldBe(visible)
  .shouldHave(cssValue("background-color", RED_COLOR), cssClass("danger-btn"));

Обновить страницу:

refresh(); // Selenide.refresh()

Псевдоклассы. Проверка что чекбокс включен:

 $("input:checked").should(exist);

Работа с localStorage:

LocalStorage localStorage = Selenide.localStorage();  
String tokensValue = localStorage.getItem("token");  // получить значение токена
localStorage.removeItem("token");                    // удалить токен

Генераторы локаторов. Useful webElement Locator generators

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

public static String insertIntoTitleStartsWith(String textInTitle) {
    // ^ нужно для поиска элементов, у которых title начинается с переданного текста
    return String.format("*[title^='%s']", textInTitle); 
}

public static String insertIntoTitle(String textInTitle) {
    return String.format("*[title='%s']", textInTitle);
}

public static String insertIntoAttribute(String attribute, String value) {
    return String.format("*[%s='%s']", attribute, value);
}

Немного про XPath

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

Кратко про XPathКратко про XPath

И какие есть этому альтернативы? Selenide умеет работать с коллекциями, и брать оттуда первый, последний и N-ный элемент из DOM-a.

/**

Если вы хотите быть уверены что все 10 элементов прогрузились,
используйте проверки на кол-во.
size(), sizeGreaterThan(), sizeGreaterThanOrEqual()
*/
ElemtntsCollection blocks = $$(BLOCK).shouldHave(size(10));

blocks.first();
blocks.last();
blocks.get(5);  // index inside

Явные (explicit waits) VS Неявные (implicit waits) ожидания

// Без ожидания условия, спящий поток
sleep(1_000);

// С ожидание условия. Используются поллинги в течение заданного таймаута
$(something).shouldBe(visible, Duration.ofSeconds(10));
  • Неявные ожидания — настраивается как глобальный конфиг таймаута для всех веб элементов. Также ожидает наступления условия и идет дальше. Так мы спасаемся от постоянных настроек Duration.ofSeconds(10)

    Каждый should содержит в себе неявное ожидание в 4 секунды, которое можно переопределить явным ожиданием в 10 секунд. Не бойтесь, под капотом используется обычный while loop.

/* Эта функция выполнится до запуска теста, и настроит неявное ожидание */
@BeforeMethod
public void configureTests() {
  Configuration.timeout = 5_000; // неявное ожидание в 5 секунд
  // ... Other browser configs
}

@Test
public void simpleTest() {
  open(URL));
  sleep(3_000);  // явно усыпить поток. Выполнение теста застынет
  $(ELEMENT).should(exist, Duration.ofSeconds(10));  // явное ожидание в 10 сек
}

Паттерны? не, не слыхал

Но возникает еще одна проблема, нагромождение текста, кода, обернутых шагов (лишних действий специфичных для системы), локаторов в самих тест кейсах. Решение: POM, POM, POM… Page Object Model — standard test automation pattern. Паттерн это набор практик, проверенных временем, и прошедших множество костылей. Нельзя просто так взять и понять POM. Напишите свою первую, вторую, третью сотку тестов (я внедрила после четырехсотки), и вы поймете что в них что-то не так, придя к моменту изучите POM.

P.S. сначала нужно наступить на грабли, перед тем как поДнять их

Из чего состоит проверка сценария?

Каждый тестируемый случай в моих авто тестах состоит из:

/*
TEST ID (идентификатор теста)
Name (название)
Description (описание)
Steps to reproduce (шаги воспроизведения)
Expected result (ожидаемый результат)
Actual result (фактический результат)
*/

Подробнее разберем состав тест кейса:

  • Ожидаемый результат — версия правильной работы, как и что должно быть

  • Фактический результат — что случилось, на каком моменте сломалось, что произошло

  • Шаги воспроизведения — самая нужная часть тест кейса, приводящая к конечному тестируемому случаю. Мастерство тестировщика в ясности и четкости (краткости) этих шагов. Не пренебрегайте этим пунктом. Без этого тест кейс не тест кейс.

  • Описание — слово само за себя, сюда можно уместить сжатую композицию шагов воспроизведения

  • Название — название функции автотеста, упрощает поиск. Рекомендую использовать или заканчивать название глаголом. SomethingShouldExist. SomethingOfTestingCase.

  • TEST ID — использую для подсчета кол-ва написанных тестов

Лайфхак. Когда падает тест, я просто копирую тест-кейс и вставляю в тикет. Хорошо когда у разработчиков развернут репо с тестами, где они сами могут запустить тест. Рядом пахнет TDD — (selenide) test driven development. В этом случае вы пишете тест до момента UI ошибки, и передаете разработчикам. Думаю это удобно. После фикса дописываете автотест и закрываете кейс.

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

Борьба с flaky тестами

Must have решения для минимизации flaky тестов. Данные решения помогут минимизировать их количество, но никак не избавиться от них полностью

  1. Перезапустить тест. Самый оптимальный вариант при крайних сроках и жестких дедлайнах.

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

  3. Test retrier — повторитель тестов. Must have штука. Обязательно научитесь. RetryAnalyzer-у (ссылочка). Очень полезная штука, проигрывается N раз, пока тест не загорит зеленым или останется красным. Минусы: действительно упавший тест будет перезагружаться N раз (суммарно займет N * times времени)

  4. UI Trigger — некий UI WebElement, настоящий delay триггер (триггер задержки) на странице, явно дающий понять что событие произошло. Наверняка большинство тестов имеют особенность падать при клике на определенный элемент. Проблема в том что не всегда ясно, завершило ли событие свое действие или имеет не тот атрибут. Например, загрузка файлов, с помощью всемогущего Селенида скачали файл, но как понять что файл был полностью передан с сервера? Поставить sleep на 10 секунд — не вариант. Нужно явно настоять программистам установить спинер или индикатор загрузки на web странице.

  5. JS Injection — об этом напишу словечко. На практике не использовала. Можно внедрить веб элементу css класс или изменить значение атрибута. Для особо отчаянных случаев.

Флоки тесты — нестабильные тесты. Временами падают, давая ложно-положительный результат. Влияют много факторов, javaScript (не до конца отрисован, всплывающие окна, возникновение скроллинга, перекрытие другим слоем или веб элементом), фреймворк, скорость работы железа, сбой в системе, маленький/fullscreen экран, сеть.

Отключить выполнение скриптов. Иногда очень полезно отключить выполнение js кода в скрипте (слишком быстрая анимация или исчезновение элемента). Сделать это можно прямо с devtools.

F12
Ctrl+Shift+P (Cmd+Shift+P)
disable JavaScript

Базовый помощник. Hot keys for IDE. Горячие клавиши — незаменимый помощник в любых ситуациях. Не усложняйте себе жизнь, научитесь им.

// Переход между вкладками
ALT + (->, <-)

// Чтобы открыть любой файл
CTRL + SHIFT + N

// Find in files
CTRL + SHIFT + F

// Format current page
CTRL + ALT + O
CTRL + ALT + L

Чем же так хорош Selenide?

Вам не нужно думать о закрытии браузера или нагромождать ваши тесты вызовом драйвера, кастомными ассертами как на голом Selenium, Selenide сделает это из под коробки. Selenium это низкоуровневый инструмент для непосредственного взаимодействия с браузером, Selenide это фреймворк, разработанный специально для UI тестирования. Разница лишь в ваших целях по применению. Лучшее сравнение Selenide и Selenium написано в официальной wiki

Напоследок

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

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

© Habrahabr.ru