1. Основы синтаксиса Java и Kotlin для нужд инженера по автоматизации
Основы синтаксиса Java и Kotlin для нужд инженера по автоматизации
Представьте, что вы пишете инструкцию для очень исполнительного, но абсолютно лишенного воображения ассистента. Если вы скажете ему: «Найди на странице кнопку входа и нажми её», он замрет в недоумении. Для него не существует «кнопки» и «нажатия», пока вы не определите эти понятия на языке ячеек памяти, условий и циклов. В автоматизации тестирования код — это не просто набор команд, а фундамент, на котором строится доверие к качеству продукта. Ошибка в синтаксисе или неверный выбор типа данных может привести к «ложноположительному» результату, когда тест проходит успешно, хотя система сломана. Мы начинаем путь с двух китов современной JVM-разработки: консервативной, структурированной Java и лаконичного, современного Kotlin.
Переменные и типы данных: фундамент тестового сценария
Любой автотест оперирует данными: URL-адреса, логины, пароли, ожидаемые тексты ошибок или количество товаров в корзине. Чтобы компьютер мог работать с этими значениями, их нужно сохранить в оперативной памяти. В Java и Kotlin для этого используются переменные.
Java — язык со строгой статической типизацией. Это значит, что вы обязаны заранее сообщить компилятору, какой тип данных будет храниться в переменной. Если вы объявили переменную как целое число, вы не сможете внезапно положить туда строку.
В Java тип данных всегда идет перед именем переменной. Это создает определенную избыточность, но делает код предсказуемым. Kotlin же предлагает механизм вывода типов (Type Inference). Если вы сразу присваиваете значение, Kotlin сам поймет, что это.
Ключевое различие, которое критически важно для QA-инженера, — это разделение на изменяемые и неизменяемые переменные в Kotlin. Использование val (value) создает константу (read-only), а var (variable) — переменную, которую можно менять. В автоматизации хорошей практикой считается использование val везде, где это возможно. Если таймаут ожидания равен 30 секундам и не должен меняться в ходе теста, val защитит вас от случайной перезаписи этого значения в другой части кода.
Примитивы против объектов
В Java существует разделение на примитивные типы (например, int, boolean, char) и ссылочные типы (объекты, такие как Integer, Boolean, String). Примитивы быстрее и занимают меньше памяти, но они не могут быть null. В автоматизации мы часто сталкиваемся с ситуациями, когда данные могут отсутствовать (например, значение из базы данных или опциональное поле в JSON-ответе).
Kotlin избавляет разработчика от явного разделения на примитивы. На уровне написания кода вы всегда используете типы вроде Int или Boolean. Компилятор сам решит, когда превратить их в примитивы для оптимизации, а когда оставить объектами.
Управляющие конструкции: логика принятия решений
Автотест — это не всегда линейная последовательность действий. Иногда нам нужно проверить: «Если появилось окно с куки, нажми "Принять", иначе продолжай работу». Или: «Повторяй попытку клика, пока элемент не станет доступным».
Условные операторы
В Java стандартный if-else выглядит классически:
Kotlin превращает if в выражение (expression). Это значит, что if может возвращать значение, которое можно сразу присвоить переменной.
Для более сложных ветвлений в Java используется switch. Однако он долгое время был громоздким. В Kotlin его заменяет мощный оператор when. Он не только лаконичнее, но и безопаснее.
Для инженера автоматизации when удобен при конфигурации тестов под разные браузеры или стенды. Вам не нужно писать каскад из if-else if, код читается как таблица соответствий.
Работа со строками: локаторы и сообщения об ошибках
Строки — это основной инструмент взаимодействия с UI. Локаторы (XPath, CSS), тексты на кнопках, сообщения валидации — всё это строки.
В Java объединение строк часто превращается в «забор» из плюсов:
String message = "Expected status " + expected + ", but got " + actual;
Это неудобно читать и легко ошибиться в пробелах. Kotlin предлагает интерполяцию строк (String Templates). Вы можете вставлять переменные прямо внутрь строки, используя символ expected, but got {}. Это избавляет от громоздкой конкатенации и делает формирование динамических локаторов (например, поиск элемента по тексту в переменной) тривиальной задачей.
Коллекции: работа с множеством элементов
Представьте, что вы тестируете поиск в интернет-магазине. Вам нужно получить список всех названий товаров на странице и проверить, что каждое из них содержит ключевое слово. Здесь вступают в дело коллекции.
В Java чаще всего используются ArrayList для списков и HashMap для пар «ключ-значение» (например, заголовки HTTP-запроса).
Kotlin делает работу с коллекциями более интуитивной, разделяя их на изменяемые (MutableList) и неизменяемые (List). По умолчанию коллекции в Kotlin неизменяемы, что предотвращает случайное изменение данных теста в методах-помощниках.
Особое внимание стоит уделить операциям над коллекциями. В современной автоматизации мы редко используем классические циклы for (int i = 0; i < list.size(); i++). Вместо этого применяются Stream API в Java или встроенные функции высшего порядка в Kotlin.
Пример на Kotlin, который поймет любой QA:
val visibleElements = allElements.filter { it.isDisplayed() }.map { it.text }
Эта строка заменяет собой 5-7 строк кода на «старой» Java, делая намерение инженера максимально прозрачным: отфильтровать только видимые элементы и собрать их тексты в новый список.
Методы и функции: переиспользование кода
Главный враг автотестов — дублирование. Если вы копируете код логина в каждый тест, то при изменении формы входа вам придется править десятки файлов. Решение — вынос логики в методы.
В Java метод всегда принадлежит классу:
В Kotlin функции объявляются ключевым словом fun. Одной из самых полезных фишек Kotlin для QA являются параметры по умолчанию.
Теперь вы можете вызвать makeScreenshot() без аргументов, или makeScreenshot("login_error"), или makeScreenshot(format = "jpg"). В Java для достижения такого же эффекта пришлось бы писать три разных метода (перегрузка методов). Это значительно сокращает объем шаблонного кода в тестовом фреймворке.
Обработка исключений: когда всё идет не по плану
В автоматизации исключения (Exceptions) — это норма жизни. Элемент не найден (NoSuchElementException), страница не загрузилась (TimeoutException), сервер вернул 500 ошибку.
Java заставляет вас обрабатывать так называемые Checkable Exceptions (проверяемые исключения) во время компиляции. Если метод «бросает» ошибку, вы обязаны либо обернуть его в try-catch, либо пробросить ошибку выше через throws.
Kotlin отказывается от концепции проверяемых исключений. Создатели языка посчитали, что это только загромождает код и заставляет разработчиков писать пустые блоки catch. В автотестах это дает свободу: вы ловите ошибки там, где действительно можете на них отреагировать (например, сделать скриншот при падении), и не пишете лишний код там, где падение теста — ожидаемый результат.
Null Safety: бич автоматизатора
Самая частая ошибка в Java-автотестах — NullPointerException (NPE). Вы пытаетесь получить текст элемента, который не был найден и вернул null. Программа падает с неинформативной ошибкой.
Kotlin решает эту проблему на уровне системы типов. Переменная не может содержать null, если вы явно этого не разрешили, добавив знак вопроса к типу:
Если вы работаете с Nullable типом, Kotlin не даст вам вызвать метод напрямую. Нужно использовать безопасный вызов ?. или оператор «Элвис» ?: для задания значения по умолчанию.
Это критически важно при парсинге сложных JSON-ответов или работе с базой данных, где часть полей может отсутствовать. Код становится «защищенным от дурака» еще на этапе написания, а не во время выполнения теста.
Пакеты и структура проекта
Для инженера по автоматизации важно понимать, как организован код. В Java и Kotlin код группируется в пакеты (packages), которые физически выглядят как папки на диске.
Обычно структура проекта в автоматизации следует стандарту Maven/Gradle:
src/main/java (или kotlin) — здесь лежат вспомогательные инструменты, Page Objects, модели данных.src/test/java (или kotlin) — здесь лежат сами тестовые сценарии.Правильное именование пакетов (например, com.company.project.pages или com.company.project.utils) помогает быстро ориентироваться в проекте, когда количество классов переваливает за сотню.
Математические операции в коде тестов
Хотя автоматизация — это не высшая математика, иногда нам нужно рассчитать ожидаемый результат. Например, проверить, что сумма товаров в корзине верна, или вычислить координаты для свайпа на мобильном устройстве.
В Java и Kotlin используются стандартные операторы: +, -, *, /, % (остаток от деления).
Важный нюанс — деление целых чисел.
В Java: ` даст результат , так как дробная часть отбрасывается.
Чтобы получить точный результат, хотя бы одно число должно быть дробным: .
Для сравнения значений используются операторы:
(равно) (не равно) (больше), < (меньше) (больше или равно), <= (меньше или равно)В Java для сравнения содержимого строк ВСЕГДА нужно использовать метод .equals(), так как == сравнивает ссылки на объекты в памяти. В Kotlin оператор == под капотом сам вызывает .equals()`, что избавляет от одной из самых коварных ошибок новичков.
Практический пример: от ручного действия к коду
Разберем простую задачу: проверка того, что цена товара на сайте не превышает бюджет.
Логика на Java:
Логика на Kotlin:
Обратите внимание, как Kotlin сокращает количество «шума» (лишних скобок, точек с запятой, явных вызовов методов получения текста). Для инженера, который пишет сотни тестов, эта лаконичность конвертируется в скорость разработки и легкость поддержки.
Освоение синтаксиса — это не заучивание словаря, а понимание логических конструкций. Java дает вам дисциплину и понимание того, как работает JVM (Java Virtual Machine), а Kotlin предоставляет современные инструменты для того, чтобы делать ту же работу быстрее и безопаснее. Эти знания станут фундаментом, когда мы перейдем к объектно-ориентированному проектированию, где переменные и методы превратятся в полноценные модели страниц и бизнес-сущностей.