Автоматизация тестирования UI и API на Kotlin

Практический курс по созданию эффективных автотестов для веб-интерфейсов и REST API с использованием языка Kotlin. Вы освоите современные библиотеки, паттерны проектирования и настройку инфраструктуры для запуска тестов.

1. Введение в Kotlin для QA: настройка окружения и основы синтаксиса

Введение в Kotlin для QA: настройка окружения и основы синтаксиса

Добро пожаловать в курс по автоматизации тестирования на Kotlin! Это первая статья, и мы начнем с самого фундамента. Kotlin за последние годы стал стандартом де-факто в разработке под Android, но его лаконичность, безопасность и полная совместимость с Java сделали его мощным инструментом и в мире Backend-разработки, и, конечно же, в автоматизации тестирования (QA Automation).

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

Почему Kotlin — отличный выбор для QA?

Прежде чем мы начнем установку, давайте поймем, почему мы вообще выбираем Kotlin для тестов:

  • Лаконичность: Тесты на Kotlin занимают меньше строк кода, чем на Java, что упрощает их чтение и поддержку.
  • Null Safety (Безопасность null): Ошибка NullPointerException — бич многих тестов. Kotlin помогает избежать её на этапе компиляции.
  • Совместимость с Java: Вы можете использовать любые Java-библиотеки (Selenium, RestAssured, Appium) без каких-либо проблем.
  • Мощные инструменты: IntelliJ IDEA (лучшая IDE для Java/Kotlin) обеспечивает великолепную поддержку языка.
  • Настройка окружения

    Для запуска автотестов нам потребуется два основных компонента: JDK (Java Development Kit) и IDE (Integrated Development Environment).

    !Структура окружения: от железа до среды разработки

    Шаг 1: Установка JDK

    Kotlin работает поверх JVM (Java Virtual Machine), поэтому наличие JDK обязательно. Мы рекомендуем использовать Amazon Corretto или Azul Zulu версии 17 или 21 (LTS — версии с долгосрочной поддержкой).

  • Перейдите на сайт Amazon Corretto.
  • Скачайте установщик для вашей операционной системы (Windows, macOS или Linux).
  • Запустите установщик и следуйте инструкциям.
  • Чтобы проверить установку, откройте терминал (или командную строку) и введите:

    Вы должны увидеть информацию о версии, например openjdk version "17.0.x".

    Шаг 2: Установка IntelliJ IDEA

    IntelliJ IDEA от JetBrains — это стандарт индустрии. Для наших задач вполне достаточно бесплатной версии Community Edition.

  • Скачайте IntelliJ IDEA Community Edition с официального сайта JetBrains.
  • Установите программу, оставляя настройки по умолчанию.
  • Шаг 3: Создание первого проекта

  • Запустите IntelliJ IDEA.
  • Нажмите New Project.
  • В поле Name введите KotlinAutomation.
  • В поле Language выберите Kotlin.
  • В поле Build system выберите Gradle (мы будем использовать Gradle Kotlin DSL — это современный стандарт).
  • В поле JDK выберите версию, которую установили на шаге 1.
  • Нажмите Create.
  • IDEA создаст структуру проекта. Подождите, пока Gradle скачает необходимые зависимости (это может занять пару минут).

    Основы синтаксиса Kotlin

    Теперь, когда проект готов, давайте изучим синтаксис. Создайте новый файл: в папке src/main/kotlin нажмите правой кнопкой мыши -> New -> Kotlin Class/File -> File -> назовите его Basics.kt.

    Точка входа: функция main

    Как и в Java или C++, выполнение программы начинается с функции main. В Kotlin она выглядит очень просто:

    Нажмите на зеленый треугольник слева от кода, чтобы запустить его. В консоли вы увидите Hello, QA World!.

    Переменные: val и var

    В Kotlin есть два способа объявить переменную. Это фундаментальное отличие, которое важно понимать для написания надежных тестов.

    val (от value*) — неизменяемая переменная (аналог final в Java). После инициализации её значение нельзя изменить. var (от variable*) — изменяемая переменная.

    > Совет: Всегда используйте val по умолчанию. Используйте var только тогда, когда это действительно необходимо. Это делает код предсказуемым и безопасным.

    Типы данных и вывод типов

    Kotlin — статически типизированный язык, но он умеет выводить типы (Type Inference). Это значит, что вам не обязательно явно указывать тип переменной, если он понятен из контекста.

    Основные типы, с которыми вы будете работать: * String — строки. * Int, Long — целые числа. * Double — числа с плавающей точкой. * Boolean — истина (true) или ложь (false).

    Строковые шаблоны (String Templates)

    Забудьте о конкатенации через +. В Kotlin можно встраивать переменные прямо в строку с помощью символа user has {experience + 1}") kotlin // Функция принимает два числа и возвращает их сумму fun sum(a: Int, b: Int): Int { return a + b }

    // Если функция ничего не возвращает, тип Unit (аналог void) можно опустить fun logMessage(message: String) { println("LOG: $message") } kotlin fun multiply(a: Int, b: Int) = a * b kotlin val a = 10 val b = 20

    // Классический вариант var max = a if (a < b) max = b

    // Вариант в стиле Kotlin val maxVal = if (a > b) a else b kotlin val statusCode = 404

    val message = when (statusCode) { 200 -> "OK" 404 -> "Not Found" 500, 502 -> "Server Error" else -> "Unknown Status" } println(message) kotlin var text: String = "Hello" // text = null // Ошибка компиляции! kotlin var nullableText: String? = "Hello" nullableText = null // Теперь это допустимо kotlin val length: Int? = nullableText?.length kotlin val length: Int = nullableText?.length ?: 0 `

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

    Заключение

    Мы настроили окружение и разобрали базовый синтаксис Kotlin. Вы узнали: * Как создавать переменные (val vs var). * Как работать со строками и шаблонами. * Как писать функции и условия. * Как Kotlin защищает нас от NullPointerException`.

    В следующей статье мы углубимся в объектно-ориентированное программирование: классы, дата-классы (незаменимы для API тестов) и коллекции.

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

    2. Автоматизация API: работа с HTTP-клиентами, сериализация данных и валидация ответов

    Автоматизация API: работа с HTTP-клиентами, сериализация данных и валидация ответов

    Приветствую вас во второй части нашего курса! В прошлой статье мы настроили окружение и познакомились с синтаксисом Kotlin. Теперь пришло время применить эти знания на практике. Мы не будем начинать с UI-тестов (Selenium/Appium), и это осознанный выбор.

    Почему? Потому что API-тесты — это фундамент пирамиды тестирования. Они быстрее, стабильнее и дешевле в поддержке, чем UI-тесты. Если вы умеете писать хорошие API-тесты на Kotlin, вы уже закрываете огромный пласт задач по обеспечению качества.

    В этой статье мы разберем:

  • Как выбрать и настроить HTTP-клиент.
  • Что такое сериализация и как Kotlin делает её элементарной.
  • Как отправлять запросы и валидировать ответы.
  • Выбор инструмента: RestAssured

    В мире Java и Kotlin стандартом де-факто для тестирования API является библиотека RestAssured. Она предоставляет удобный DSL (Domain Specific Language) для написания тестов в стиле BDD (Behavior Driven Development): Given-When-Then (Дано-Когда-Тогда).

    Конечно, существуют и другие клиенты, например, Retrofit (популярен в Android-разработке) или Ktor Client (нативный Kotlin-клиент). Но для QA Automation RestAssured остается лидером благодаря своей простоте и мощным возможностям валидации «из коробки».

    Настройка зависимостей

    Откройте ваш проект в IntelliJ IDEA. Нам нужно добавить библиотеки в файл сборки. Найдите файл build.gradle.kts (Kotlin DSL) и добавьте в блок dependencies следующие строки:

    После добавления нажмите кнопку Load Gradle Changes (значок слона с синими стрелками), чтобы скачать библиотеки.

    Анатомия HTTP-запроса

    Прежде чем писать код, давайте вспомним, как работает общение с API. Это всегда диалог между Клиентом (наш автотест) и Сервером.

    !Визуализация цикла запрос-ответ в протоколе HTTP

    Любой запрос состоит из: * URL: Куда стучимся (например, https://reqres.in/api/users). * Method: Что хотим сделать (GET — получить, POST — создать, PUT — обновить, DELETE — удалить). * Headers: Метаданные (например, Content-Type: application/json). * Body: Тело запроса (данные, которые мы отправляем, актуально для POST/PUT).

    Ваш первый API-тест на Kotlin

    Давайте напишем тест, который проверяет получение списка пользователей. Мы будем использовать публичный тестовый API ReqRes.

    Создайте файл UsersApiTest.kt в папке src/test/kotlin.

    Обратите внимание на использование обратных кавычек в названии функции: ` should return... . В Kotlin это допустимо для тестов и позволяет писать читаемые названия сценариев с пробелами.

    Также обратите внимание на .when(). Так как when — это ключевое слово в Kotlin (аналог switch), в коде Java-библиотек его приходится экранировать обратными кавычками.

    Сериализация и Data Classes: Суперсила Kotlin

    В примере выше мы просто получили JSON как текст. Но работать с текстом неудобно. Мы хотим работать с объектами.

    Процесс превращения объекта в JSON называется сериализацией, а обратный процесс (JSON в объект) — десериализацией.

    В Java для этого приходилось писать громоздкие POJO (Plain Old Java Objects) с геттерами, сеттерами, equals() и hashCode(). В Kotlin для этого есть Data Classes.

    Предположим, мы хотим создать нового пользователя. API ожидает такой JSON:

    Создадим для этого Data Class. В одном файле с тестом (или в отдельном файле) добавьте:

    > Важно: Для корректной работы Jackson (библиотеки сериализации) с Kotlin иногда требуется пустой конструктор или специальные аннотации, но модуль jackson-module-kotlin, который мы подключили, умеет работать с data-классами нативно.

    Тестирование POST-запроса

    Теперь напишем тест на создание пользователя, используя наши классы.

    Разбор происходящего

  • val requestBody = UserRequest(...): Мы создали обычный Kotlin-объект. Нам не нужно вручную склеивать строку JSON.
  • .body(requestBody): Библиотека RestAssured увидела объект, поняла, что Content-Type установлен в JSON, и с помощью Jackson превратила объект в строку {"name":"Morpheus",...}.
  • .extract().as(UserResponse::class.java): Мы взяли JSON-ответ от сервера и превратили его обратно в типизированный объект UserResponse. Теперь мы можем обращаться к полям через точку: response.id.
  • Валидация ответов

    Валидация — это сердце автотеста. Если вы не проверили данные, тест бесполезен.

    Проверка статус-кодов

    Всегда начинайте с проверки HTTP Status Code. * 2xx — Успех (200 OK, 201 Created, 204 No Content). * 4xx — Ошибка клиента (400 Bad Request, 401 Unauthorized, 404 Not Found). * 5xx — Ошибка сервера (500 Internal Server Error, 502 Bad Gateway).

    Проверка тела ответа (Body)

    Есть два пути:

  • Inline-проверки (через Hamcrest). Удобно для простых проверок без создания классов.
  • Десериализация и AssertJ. Удобно для сложной логики (как в примере с POST-запросом выше). Это предпочтительный путь для Kotlin, так как он типобезопасен.
  • Обработка Nullable полей

    В API часто бывает, что какое-то поле может прийти, а может и нет (быть null). Kotlin заставляет нас явно это обрабатывать.

    Если поле в JSON может быть null, в Data Class вы обязаны пометить его вопросительным знаком:

    Если вы забудете ?, а сервер пришлет null`, тест упадет с ошибкой десериализации. Это отличный пример того, как Kotlin помогает находить баги контрактов API еще на этапе написания кода.

    Заключение

    Сегодня мы научились: * Подключать RestAssured в проект на Gradle. * Понимать разницу между сериализацией и десериализацией. * Использовать Data Classes для описания моделей данных. * Писать полноценные тесты с проверками (Assertions).

    В следующей статье мы перейдем к UI-тестированию: настроим Selenium WebDriver, узнаем про паттерн PageObject и научимся управлять браузером с помощью кода.

    А пока — выполните домашнее задание, чтобы закрепить материал!

    3. UI-тестирование веб-приложений: использование Selenide и паттерна Page Object

    UI-тестирование веб-приложений: использование Selenide и паттерна Page Object

    Добро пожаловать в третью часть нашего курса! Мы уже научились настраивать окружение, освоили основы Kotlin и научились тестировать API с помощью RestAssured. Теперь мы поднимаемся на вершину пирамиды тестирования — к UI-тестам.

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

    В этой статье мы познакомимся с библиотекой Selenide и архитектурным паттерном Page Object, который спасет ваши тесты от хаоса.

    Почему Selenide, а не Selenium?

    Вы наверняка слышали про Selenium WebDriver. Это стандарт индустрии, инструмент, который позволяет управлять браузером через код. Но писать тесты на «голом» Selenium — это боль:

  • Нужно вручную управлять драйвером (скачивать, запускать, закрывать).
  • Нужно писать много кода для ожидания элементов (Explicit Waits).
  • Код получается громоздким и трудночитаемым.
  • Selenide — это обертка над Selenium WebDriver, созданная специально для автоматизированного тестирования. Она решает все вышеперечисленные проблемы.

    > Selenide — это Selenium для людей.

    Основные преимущества Selenide: * Умные ожидания: Selenide сам ждет, пока элемент появится, станет видимым или кликабельным. * Автоматическое управление драйвером: Вам не нужно скачивать chromedriver.exe. * Лаконичный синтаксис: ("[name='q']").setValue("Selenide").pressEnter()

    // 3. Проверяем, что первый результат поиска виден и содержит текст ("selector"): Аналог driver.findElements. Возвращает коллекцию элементов ElementsCollection.

  • shouldHave, shouldBe: Методы для проверок (ассертов). Если условие не выполнится за 4 секунды (настройка по умолчанию), тест упадет и сделает скриншот.
  • Проблема простых тестов

    Код выше выглядит просто, но представьте, что у вас 50 тестов, и в каждом вы ищете строку поиска через `

    class GooglePage { // Описываем элементы как свойства класса // Важно: поиск элемента происходит не при создании объекта, // а в момент обращения к нему (Lazy evaluation) private val searchInput = ("[name='btnK']")

    // Методы взаимодействия (Actions) fun search(query: String) { searchInput.setValue(query).pressEnter() } } kotlin import com.codeborne.selenide.CollectionCondition.sizeGreaterThan import com.codeborne.selenide.Condition.text import com.codeborne.selenide.Selenide.("div.g")

    fun checkResultsSize(expectedSize: Int) { results.shouldHave(sizeGreaterThan(expectedSize)) }

    fun checkFirstResultHasText(expectedText: String) { results.first().shouldHave(text(expectedText)) } } kotlin import com.codeborne.selenide.Selenide.open import org.junit.jupiter.api.Test

    class GooglePageObjectTest {

    @Test fun should search using page object() { open("https://google.com")

    val googlePage = GooglePage() googlePage.search("Kotlin Automation")

    val resultsPage = SearchResultsPage() resultsPage.checkResultsSize(5) resultsPage.checkFirstResultHasText("Kotlin") } }

    Скриншоты при падении

    Selenide автоматически делает скриншот и сохраняет HTML-код страницы, если тест упал. Вам не нужно ничего настраивать. Ищите папку build/reports/tests после прогона.

    Лучшие практики UI-тестирования

  • Атомарность: Один тест должен проверять одну конкретную функцию. Не пытайтесь проверить весь сайт в одном сценарии.
  • Независимость: Тесты не должны зависеть друг от друга. Если один тест упал, остальные должны работать.
  • Стабильные селекторы: Старайтесь использовать уникальные атрибуты, такие как data-testid или id. Избегайте селекторов вида div > div:nth-child(3) > span, так как они ломаются при любом изменении дизайна.
  • Не используйте Thread.sleep(): Никогда. Это замедляет тесты и делает их нестабильными. Используйте should условия Selenide, они сами подождут нужное время.
  • Заключение

    Сегодня мы сделали большой шаг вперед: * Познакомились с Selenide и поняли, почему он лучше чистого Selenium. * Написали первый UI-тест. * Разобрали паттерн Page Object и применили его на практике.

    Теперь ваш арсенал включает и API, и UI тесты. В следующей статье мы поговорим о том, как объединить эти знания и построить красивый отчет о тестировании с помощью Allure Report.

    Выполните домашнее задание, чтобы закрепить материал!

    4. Построение отчетности с Allure Report и интеграция тестов в CI/CD

    Построение отчетности с Allure Report и интеграция тестов в CI/CD

    Поздравляю! Вы прошли огромный путь. Мы начали с настройки Kotlin, научились писать быстрые API-тесты на RestAssured и стабильные UI-тесты на Selenide с использованием Page Object. У нас есть код, который проверяет качество продукта.

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

    В этой финальной статье мы превратим ваш набор тестов в полноценный инструмент качества:

  • Подключим Allure Report для создания красивых и понятных отчетов.
  • Настроим CI/CD через GitHub Actions, чтобы тесты запускались автоматически.
  • Allure Report: Делаем тесты прозрачными

    Allure Framework — это гибкий инструмент для построения отчетов о тестировании. Он не просто показывает «зеленые» и «красные» тесты, но и предоставляет подробную информацию: шаги выполнения, скриншоты, логи запросов и статистику стабильности.

    !Схема генерации отчета: от выполнения тестов до HTML-страницы

    Шаг 1: Подключение Allure в Gradle

    Откройте файл build.gradle.kts. Нам нужно добавить плагин и библиотеку адаптера для JUnit 5.

    После изменения файла не забудьте нажать Load Gradle Changes.

    Шаг 2: Разметка тестов аннотациями

    Allure позволяет добавлять метаданные к тестам, чтобы отчет был информативным. Давайте улучшим наш API-тест из второй статьи.

    Теперь в отчете вместо одной строки «Test Passed» будет красивое дерево шагов: «Подготовка данных» -> «Отправка запроса» -> «Проверка».

    Шаг 3: Интеграция с Selenide (Скриншоты)

    Самое ценное в UI-тестах — видеть, что произошло в момент падения. Selenide умеет делать скриншоты, но нам нужно передать их в Allure. Это делается одной строкой кода.

    В классе с настройками тестов (или в методе @BeforeEach) добавьте:

    Теперь при каждом падении теста в отчет будет автоматически прикрепляться скриншот и HTML-код страницы.

    Шаг 4: Генерация отчета локально

    Чтобы посмотреть отчет на своем компьютере, выполните в терминале:

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

    CI/CD: Автоматизация запуска

    CI (Continuous Integration) — это практика, при которой изменения в коде автоматически собираются и тестируются. Мы будем использовать GitHub Actions, так как он бесплатен для публичных репозиториев и тесно интегрирован с GitHub.

    Наша цель: при каждом push (отправке кода) в репозиторий GitHub должен:

  • Арендовать виртуальную машину (Runner).
  • Установить туда Java.
  • Запустить наши тесты.
  • Сформировать Allure-отчет.
  • Опубликовать отчет на GitHub Pages, чтобы мы могли отправить ссылку коллегам.
  • !Конвейер автоматизации: от коммита до публикации отчета

    Подготовка UI-тестов для CI (Headless Mode)

    На серверах GitHub Actions нет монитора. Если вы попытаетесь запустить браузер в обычном режиме, тесты упадут. Нужно включить Headless режим (браузер работает в памяти без графического интерфейса).

    Добавьте настройку в ваш базовый класс тестов:

    > Совет: Лучше выносить этот параметр в переменные окружения, чтобы локально запускать с браузером, а на CI — без. Но для начала можно просто включить true.

    Создание Workflow файла

    В корне вашего проекта создайте структуру папок: .github/workflows. Внутри создайте файл test.yml.

    Вставьте туда следующий код (YAML чувствителен к отступам!):

    Что здесь происходит?

  • on: push: Триггер запуска. Пайплайн стартует при каждом обновлении ветки main.
  • runs-on: ubuntu-latest: Мы просим GitHub выделить нам сервер на Linux.
  • ./gradlew test: Запуск тестов. Обратите внимание на continue-on-error: true. Если тесты найдут баг и упадут, Gradle вернет ошибку. Обычно это останавливает пайплайн. Но нам нужно продолжить, чтобы сгенерировать отчет и увидеть почему они упали.
  • peaceiris/actions-gh-pages: Это готовый экшен, который берет папку с отчетом и отправляет её в специальную ветку gh-pages вашего репозитория.
  • Настройка репозитория

    Чтобы публикация сработала, нужно разрешить GitHub Actions запись в репозиторий:

  • Зайдите в настройки репозитория на GitHub (Settings).
  • Перейдите в Actions -> General.
  • В разделе Workflow permissions выберите Read and write permissions.
  • Нажмите Save.
  • Теперь сделайте git add, git commit и git push. Перейдите во вкладку Actions в репозитории — вы увидите, как запустился ваш процесс.

    Когда процесс завершится (станет зеленым), перейдите в Settings -> Pages. Там должна появиться ссылка на ваш опубликованный сайт с отчетом. Обычно она выглядит как https://<ваш-логин>.github.io/<имя-проекта>/.

    Анализ результатов

    Открыв ссылку, вы увидите дашборд Allure.

    * Suites: Список тест-кейсов, сгруппированный по классам. * Graphs: Графики прохождения тестов. * Behaviors: Если вы использовали аннотации @Feature и @Story, тесты будут сгруппированы по функциональности.

    Если UI-тест упал, зайдите в него, и вы увидите раздел Test body, где будет прикреплен скриншот состояния страницы в момент ошибки. Это бесценно для отладки.

    Заключение курса

    Поздравляю! Вы завершили курс «Автоматизация тестирования UI и API на Kotlin».

    Давайте вспомним, чему вы научились:

  • Kotlin: Вы освоили современный, безопасный и лаконичный язык программирования.
  • API Testing: Вы научились отправлять запросы и валидировать ответы с RestAssured и Data Classes.
  • UI Testing: Вы освоили Selenide и паттерн Page Object для создания надежных браузерных тестов.
  • Reporting & CI/CD: Вы настроили автоматический запуск тестов в облаке и генерацию профессиональных отчетов.
  • Теперь у вас есть полный набор навыков для работы на позиции QA Automation Engineer (Kotlin). Практикуйтесь, пишите больше тестов и не бойтесь изучать новые инструменты!

    Удачи в автоматизации!

    5. Архитектура тестового фреймворка: лучшие практики, логирование и параллельный запуск

    Архитектура тестового фреймворка: лучшие практики, логирование и параллельный запуск

    Приветствую вас в завершающей части нашего курса! Мы прошли долгий путь: от «Hello World» на Kotlin до настройки CI/CD пайплайнов. У вас уже есть набор работающих тестов для API и UI. Но по мере роста проекта количество тестов будет увеличиваться с десятков до сотен и тысяч.

    В этот момент вы столкнетесь с новыми проблемами:

  • Время выполнения: Последовательный запуск 500 UI-тестов может занять 5-6 часов. Это слишком долго для получения обратной связи.
  • Сложность поддержки: Если изменение одной кнопки на сайте ломает 50 тестов в разных местах, значит, архитектура хромает.
  • Отладка: Когда тест падает в CI, сообщения «Element not found» недостаточно. Нужно понимать, что происходило в системе за секунду до падения.
  • В этой статье мы превратим набор разрозненных скриптов в мощный, масштабируемый Test Automation Framework. Мы обсудим правильную архитектуру, настроим профессиональное логирование и научимся запускать тесты параллельно, сокращая время прогона в разы.

    Слоистая архитектура (Layered Architecture)

    Главный враг автоматизатора — спагетти-код, где в одном методе смешаны HTTP-запросы, клики по кнопкам, проверки базы данных и бизнес-логика. Чтобы этого избежать, мы должны разделять код на слои.

    !Схема разделения ответственности в тестовом фреймворке

    1. Слой данных (Data Layer)

    Здесь живут наши Data Classes, которые мы изучили во второй лекции. Этот слой ничего не знает о Selenium или RestAssured. Это чистые объекты (POJO/POKO).

    2. Слой взаимодействия (Interaction Layer)

    Здесь находится код, который «трогает» приложение. * Для UI это Page Objects (как мы делали с Selenide). * Для API это API Clients (обертки над RestAssured).

    Этот слой не должен содержать ассертов (проверок). Его задача — выполнить действие и вернуть результат (текст, число или другую страницу).

    3. Слой бизнес-логики (Business Layer / Steps)

    Иногда одно действие пользователя требует работы с несколькими страницами или API. Например, «Регистрация пользователя» может включать:

  • API-запрос на создание аккаунта (чтобы не проходить капчу).
  • Открытие почтового ящика (API или UI).
  • Клик по ссылке подтверждения.
  • Такие цепочки действий удобно выносить в Steps (Шаги). В Kotlin это часто реализуется через Extension Functions или отдельные классы-сервисы.

    4. Слой тестов (Test Layer)

    Здесь живут методы с аннотацией @Test. Тесты должны быть: * Короткими: 5-15 строк кода. * Декларативными: Читаться как сценарий на английском языке. * Независимыми: Каждый тест сам готовит себе данные и чистит их за собой.

    Логирование: проливаем свет на происходящее

    System.out.println("Test started") — это плохая практика. В многопоточной среде консольный вывод превратится в кашу. Нам нужен профессиональный инструмент.

    В мире Java/Kotlin стандартом является связка SLF4J (интерфейс) и Logback (реализация).

    Подключение зависимостей

    Добавьте в build.gradle.kts:

    Настройка Logback

    Создайте файл src/test/resources/logback.xml. В нем мы укажем, как и куда писать логи.

    Использование в коде

    В Kotlin удобно создать отдельный объект или использовать функцию для получения логгера.

    Логирование API и UI

    Для RestAssured добавьте фильтры, чтобы видеть запросы и ответы:

    Для Selenide логирование действий включено по умолчанию, но его можно расширить, добавив SelenideLogger (как мы делали для Allure).

    Параллельный запуск тестов

    Это «святой грааль» автоматизации. Если у вас 100 тестов, и каждый идет 10 секунд, последовательный запуск займет ~17 минут. Запуск в 10 потоков сократит это время до ~2 минут.

    JUnit 5 имеет встроенную поддержку параллелизма, но ее нужно включить.

    Настройка JUnit 5

    Создайте файл src/test/resources/junit-platform.properties:

    Главная опасность: Thread Safety (Потокобезопасность)

    При параллельном запуске несколько тестов работают одновременно. Если они используют общие ресурсы, произойдет катастрофа.

    Пример плохой архитектуры:

    !Иллюстрация состояния гонки при использовании общих ресурсов

    Правила безопасности:

  • Избегайте object (синглтонов) с изменяемым состоянием (var). Используйте val или создавайте новые объекты внутри теста.
  • Selenide потокобезопасен. Selenide автоматически создает отдельный экземпляр WebDriver для каждого потока. Вам не нужно об этом беспокоиться, если вы не используете статический WebDriverRunner.getWebDriver() для ручных манипуляций.
  • Изоляция данных. Если Тест А и Тест Б редактируют одного и того же пользователя в БД одновременно, они упадут. Каждый тест должен создавать своего уникального пользователя (например, с рандомным email).
  • Управление конфигурацией (Environment)

    Тесты часто запускаются на разных окружениях: dev, stage, prod. Хардкодить URL (https://stage.mysite.com) в коде — плохая практика.

    Используйте библиотеку Owner или стандартные Properties.

    Пример простого решения на Kotlin:

    Теперь вы можете менять окружение при запуске из терминала:

    Лучшие практики (Best Practices)

    Подводя итог всему курсу, выделим золотые правила:

  • KISS (Keep It Simple, Stupid). Не усложняйте архитектуру без нужды. Если у вас 10 тестов, вам не нужен сложный фреймворк с Dependency Injection.
  • DRY (Don't Repeat Yourself). Если вы копируете код логина в третий раз — вынесите его в метод login() в BaseTest или PageObject.
  • Fluent Interface. Делайте методы PageObject так, чтобы они возвращали this или следующую страницу. Это позволяет писать цепочки:
  • Fail Fast. Если тест не может выполнить предусловие (например, API не вернул пользователя), он должен упасть сразу, а не пытаться кликать по UI.
  • Заключение курса

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

    Вы знаете: * Синтаксис Kotlin и его фишки (Null Safety, Data Classes). * Как тестировать API с RestAssured. * Как писать стабильные UI-тесты на Selenide. * Как генерировать отчеты Allure и запускать тесты в CI/CD. * Как масштабировать тесты через параллельный запуск.

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

    А теперь — финальное домашнее задание.