← Java

Конспект і таймкоди

0:00

Від простого тесту до підтримуваного коду

Викладач порівнює початковий тест із читабельнішою версією, де послідовність кроків винесена в методи. Такий проміжний варіант полегшує читання, але накопичує всі дії в одному класі, тому його потрібно далі розділити за сторінками.

Рефакторинг пояснюється через взаємодоповнювальні принципи. KISS вимагає починати з найпростішого рішення, яке працює; YAGNI — не додавати бібліотеки, підписки, Page Object або AI-інструменти до появи реальної потреби; DRY — помічати дублювання, але не виносити кожен повтор механічно; DAMP — давати змінним, методам і класам описові та змістовні назви. Надмірна архітектура на старті ускладнює супровід та онбординг, а називання сутностей стає легшим лише з практикою.

8:44

Page Object, пакети та доступність залежностей

Page Object визначається як клас, що описує логічну частину сторінки: цілу сторінку або окремий повторно використовуваний компонент. Для початкового варіанта кожна сторінка отримує окремий клас із діями, доступними користувачеві на ній.

У src/main/java створюється окрема структура пакетів для вебчастини та сторінок. Після перенесення методу авторизації Selenide стає недоступним у production-коді, бо залежність оголошена через testImplementation; її змінюють на implementation, тоді як test runner залишається лише в тестовій області. Після синхронізації Gradle IntelliJ IDEA може додати потрібні імпорти через quick fix; невикористані імпорти потрібно регулярно прибирати.

15:33

Інстанси, `static` і назви сторінок

Для Page Object обирається об'єктноорієнтований підхід без static: метод викликається через створений інстанс класу. Сторінку перейменовують із LoginPage на SignInPage, оскільки назву sign in уже використовує сам продукт. У Java назва public-класу має збігатися з назвою файлу, тому для перейменування застосовується рефакторинг IntelliJ IDEA, а не ручна заміна тексту.

Метод у SignInPage називається просто open, без дублювання назви класу у openSignInPage. Базовий домен задається один раз через Configuration.baseUrl, після чого Selenide open може приймати лише шлях сторінки. Це прибирає повторення домену з Page Object-методів.

24:00

Клас, об'єкт і повторне використання Page Object

Клас пояснюється як інструкція, що описує дані й поведінку, а об'єкт — як екземпляр цієї інструкції під час виконання в JVM. Щоб не створювати новий SignInPage перед кожним викликом, посилання на один інстанс зберігається у змінній й повторно використовується для open та авторизації.

Для локальних змінних Java дозволяє var, коли компілятор може вивести тип із правої частини ініціалізації. Для поля класу такий запис у показаному прикладі не використовується. Після кожного невеликого перенесення викладач запускає тест, щоб одразу виявляти поломки.

30:00

Рефакторинг сторінки зі списком проєктів

Сторінка після авторизації отримує назву ProjectsPage, бо вона містить список, пошук і вибір проєктів. Її open викликає Selenide явно: випадковий виклик однойменного методу самого класу створив би рекурсію та завершився StackOverflowError. IntelliJ IDEA підказує кваліфікувати виклик через Selenide.

Методи відкриття, пошуку та вибору проєкту переносяться в ProjectsPage, а тест зберігає один інстанс цього класу. Викладач розрізняє declaration змінної та initialization об'єкта, використовує автодоповнення і після кожного кроку повторно запускає тест. Для базового URL попереджається про ризик випадкових подвійних слешів.

39:02

Методи Java та генерація за місцем виклику

Показано, що Java-клас успадковує методи Object, зокрема equals, hashCode, getClass, toString, notify, wait та інші. Підказки IntelliJ IDEA відображають ці успадковані методи навіть тоді, коли вони не оголошені безпосередньо в Page Object.

Новий метод можна спочатку викликати в тесті, а потім створити в цільовому Page Object через quick fix Create method. IDE переносить назву й параметри з місця виклику, після чого до згенерованого методу додається реальна реалізація. У контексті Java викладач уточнює, що такі функції класу коректно називаються методами.

43:10

Loadable Component і стабільні переходи

Для кожної сторінки створюється метод isLoaded, який очікує на характерний елемент через Selenide shouldBe(Condition.visible). Цей підхід названо патерном Loadable Component. Перевірка завантаження має належати цільовій сторінці: SignInPage не повинен перевіряти внутрішні елементи наступної сторінки.

Перехід можна додатково стабілізувати очікуванням, що елементи попередньої сторінки стали прихованими через shouldBe(Condition.hidden). Таким чином тест підтверджує і зникнення попереднього стану, і завантаження наступного. Після вибору проєкту створюється окремий ProjectPage, назву якого виводять із URL та структури продукту.

49:58

`ProjectPage`, діагностика падіння та коректна відповідальність

Назва ProjectPage обирається після аналізу URL, HTML і функцій сторінки: вона охоплює не лише тест-кейси, а й налаштування, шаблони та користувачів проєкту. Методи isLoaded у ProjectsPage і ProjectPage роблять public, щоб тест міг явно перевіряти кожний перехід.

Під час запуску тест падає через неперевірений селектор. Викладач знаходить перший релевантний рядок власного коду у stack trace, звіряє DOM і переносить перевірку повідомлення про успішний вхід до відповідальнішого місця. Характерний пошуковий елемент зберігається в полі Page Object і повторно використовується для перевірки завантаження, після чого тест знову проходить.

1:01:50

Дії, очікування та значення для перевірки

Дії та динамічні очікування переносяться в Page Object у порядку, в якому їх викликає сценарій. Перевірку точного тексту можна інкапсулювати методом, що приймає очікуване значення і використовує Selenide shouldHave. Це дозволяє Selenide чекати, доки елемент набуде потрібного стану.

Якщо перевірка потребує довільної логіки, наприклад порівняння кількості тест-кейсів із порогом, Page Object повертає текст або оброблене значення, а assertion залишається в тесті. TestNG не переносять до src/main/java; production-частина отримує дані зі сторінки, тест явно формулює очікування. Викладач рекомендує динамічні очікування там, де це можливо, замість одноразового читання нестабільного UI.

1:10:00

Стабілізація перевірок і підготовка коду до коміту

Перед статичним читанням тексту додається очікування видимості елемента, щоб уникнути перевірки ще не завантаженого стану. Page Object може містити очікування того, що користувач бачить на сторінці, тоді як тест зберігає бізнес-порівняння отриманого значення. Після рефакторингу сценарій читається як послідовність дій через SignInPage, ProjectsPage і ProjectPage, а реалізація рознесена між відповідними класами.

Наприкінці показано Reformat Code та Optimize Imports: IDE прибирає зайві імпорти й упорядковує статичні та нестатичні поля й методи. Автоматичне форматування перед комітом не замінює запуск тестів, бо зміна порядку ініціалізації може зламати код. Звичка — очистити імпорти, відформатувати код і перевірити його до коміту.

1:16:56

Підсумок і практика іменування

Заняття підсумовує перехід від простого KISS-тесту, доповненого YAGNI, DRY і DAMP, до Page Object-структури з очікуваннями та двома способами перевірок: очікувати значення безпосередньо в об'єкті сторінки або повернути дані в тест для окремого порівняння.

Для іменування класів, методів, змінних і тестів радять використовувати терміни, уже закладені розробниками: назви з URL, HTML та мережевих запитів, а також фактичні дії користувача. Наступні тести пропонується одразу писати через Page Object і вдосконалювати назви практикою.