Путь в QA Automation: от основ Java до создания первого тестового фреймворка

Интенсивный курс для ручных тестировщиков, обеспечивающий плавный переход к автоматизации на Java. Программа выстроена от базового синтаксиса и логики программирования до проектирования масштабируемых автотестов с использованием Selenium и TestNG.

Введение в автоматизацию: настройка среды разработки и первая программа на Java

Введение в автоматизацию: настройка среды разработки и первая программа на Java

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

Чтобы компьютер начал выполнять наши тестовые сценарии, нам нужно научиться говорить с ним на одном языке. В нашем курсе этим языком будет Java — один из самых популярных и надежных языков в сфере QA Automation. Но прежде чем написать первую команду, нам нужно подготовить рабочее место.

Инструменты инженера по автоматизации

В ручном тестировании ваши главные инструменты — это браузер, система отслеживания задач (например, Jira) и инструменты разработчика (DevTools). В автоматизации на Java базовый набор состоит из двух фундаментальных компонентов: JDK и IDE.

Частая ошибка новичков — путать язык программирования, среду для его запуска и программу, в которой пишется код. Давайте разделим эти понятия.

Компонент Расшифровка Роль в автоматизации Аналогия из жизни
JDK Java Development Kit (Набор разработчика Java) Предоставляет компилятор и библиотеки, необходимые для перевода вашего кода на язык, понятный компьютеру. Без него Java-код — просто текст. Двигатель автомобиля. Он скрыт под капотом, но именно он заставляет машину ехать.
IDE Integrated Development Environment (Интегрированная среда разработки) Программа, в которой вы пишете код. Она подсвечивает ошибки, подсказывает команды и позволяет запускать тесты одной кнопкой. Приборная панель и руль. Это удобный интерфейс для управления двигателем.

Среда разработки (IDE) не заменяет знание языка, но она берет на себя всю черновую работу: от форматирования текста до автоматического поиска пропущенных точек с запятой.

Роберт Мартин, "Чистый код"

Для нашего курса мы будем использовать IntelliJ IDEA Community Edition — это бесплатная версия самой популярной IDE в мире Java, которая стала индустриальным стандартом для QA-инженеров.

Настройка рабочего окружения

Чтобы подготовить систему к написанию автотестов, нужно выполнить два шага в строгой последовательности: сначала ставим «двигатель», затем «приборную панель».

  1. Установка JDK. Для работы нам потребуется версия Java не ниже 11-й (рекомендуется использовать версии с долгосрочной поддержкой — LTS, например, JDK 17 или 21). Скачать установочный файл можно с сайтов Oracle или Adoptium. Процесс установки ничем не отличается от установки любой обычной программы: достаточно нажимать «Далее».
  2. Установка IntelliJ IDEA. Скачайте версию Community Edition с официального сайта JetBrains. После установки и первого запуска программа сама найдет установленный на предыдущем шаге JDK и свяжет его с вашими будущими проектами.

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

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

В программировании есть традиция — начинать изучение нового языка с программы, которая выводит на экран фразу «Hello, World!». Но так как наша цель — тестирование, мы напишем программу, которая сообщит нам, что система готова к запуску автотестов.

Откройте IntelliJ IDEA, создайте новый проект (New Project), назовите его QaAutomationBasics и убедитесь, что в поле JDK выбрана установленная вами версия Java.

Внутри проекта создайте файл с именем FirstTest.java и напишите в нем следующий код:

public class FirstTest {
    public static void main(String[] args) {
        System.out.println("Тестовое окружение готово к работе!");
    }
}

После того как вы нажмете зеленую кнопку запуска (Run) рядом с кодом, в нижней части экрана откроется окно консоли, где появится текст: Тестовое окружение готово к работе!

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

Анатомия первого скрипта

Java — язык со строгими правилами. В отличие от ручного тест-кейса, где шаг «нажми кнопку» можно описать десятком разных фраз, компьютер требует абсолютной точности. Разберем написанный код по частям.

Класс как контейнер

Первая строка public class FirstTest объявляет класс. В Java весь код должен находиться внутри классов. Пока что можете думать о классе как о шкафчике, в котором хранятся инструменты для определенной задачи.

Важное правило Java, нарушение которого сразу приведет к ошибке: имя класса должно в точности совпадать с именем файла. Если файл называется FirstTest.java, то и класс должен называться FirstTest. Фигурные скобки { } обозначают границы этого класса — начало и конец шкафчика.

Точка входа

Вторая строка public static void main(String[] args) — это метод main. Когда вы нажимаете кнопку «Run», компьютер не читает код сверху вниз, как книгу. Он целенаправленно ищет метод с именем main. Это стартовая черта вашей программы, точка входа. Если в классе нет метода main, программа просто не поймет, откуда начинать работу, и не запустится.

Действие

Третья строка System.out.println("Тестовое окружение готово к работе!"); — это сама команда.

  • System.out обращается к стандартному выводу системы (нашему экрану).
  • println (сокращение от print line) приказывает напечатать текст и перевести курсор на новую строку.
  • Текст, который мы хотим вывести, обязательно берется в двойные кавычки " ".
  • В конце строки стоит точка с запятой ;. Это аналог точки в конце предложения в русском языке. Она говорит компьютеру: «Команда завершена, переходи к следующей».

Что дальше?

Сегодня мы заложили фундамент: настроили связку JDK + IDE и разобрали структуру минимальной Java-программы. Вы увидели, как текст в редакторе превращается в результат в консоли.

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

Типы данных и переменные: как Java хранит и обрабатывает информацию для тестов

Типы данных и переменные: как Java хранит и обрабатывает информацию для тестов

Когда вы тестируете приложение вручную, вы постоянно держите в голове или в блокноте тестовые данные: логин «test_user», пароль «QWERTY123», ожидаемую цену товара 199.99 и статус-код успешного ответа 200. В прошлой главе мы научили программу выводить фиксированный текст в консоль, но реальный автотест не может состоять только из статичных фраз. Ему нужно «запоминать» вводные данные, подставлять их в поля, извлекать результаты с веб-страницы и сравнивать их с ожидаемыми. Для этого в программировании существуют переменные.

Переменные и строгая типизация

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

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

Однако Java — язык со строгой статической типизацией. Это значит, что вы не можете взять любую коробку и положить туда что угодно. При создании переменной вы обязаны заранее объявить, какой именно тип данных в ней будет храниться. Если вы создали коробку для целых чисел, положить туда текст уже не получится — программа просто не скомпилируется и выдаст ошибку еще до запуска.

Чтобы создать переменную (этот процесс называется объявлением), нужно написать тип данных, затем имя переменной, и через знак равенства присвоить ей значение (это называется инициализацией):

ТипДанных имяПеременной = значение;

Имя переменной в Java принято писать в стиле camelCase (верблюжий регистр): слово начинается со строчной буквы, а каждое следующее слово внутри имени — с заглавной, без пробелов. Например: loginButton, expectedStatusCode, userPassword.

Базовый арсенал тестировщика: 4 главных типа данных

В Java существует множество типов данных, но для написания 90% автотестов на старте вам понадобятся всего четыре. Три из них — это так называемые примитивные типы (простые значения), и один — ссылочный (сложный объект).

1. int (целые числа)

Используется для хранения любых целых чисел без дробной части. В автотестах мы применяем int для проверки HTTP статус-кодов, подсчета количества элементов на странице (например, сколько товаров в корзине) или хранения ID пользователя.

int statusCode = 200;
int itemsInCart = 3;

2. double (числа с плавающей точкой)

Если тестируемый продукт связан с финансами, скидками, весом или точными измерениями времени отклика, вам понадобятся дробные числа. В Java дробная часть отделяется точкой, а не запятой.

double productPrice = 99.99;
double loadTimeSeconds = 1.5;

3. boolean (логический тип)

Самый важный тип для проверок (ассертов). Он может хранить только два значения: true (истина) или false (ложь). Любой автотест в конечном итоге сводится к логическому утверждению: совпадает ли фактический результат с ожидаемым? Если A=BA = B, то результат true — тест пройден. Если A≠BA \neq B, то false — тест упал.

boolean isUserLoggedIn = true;
boolean isErrorDisplayed = false;

4. String (текстовые строки)

Текст — это основа UI и API тестирования. URL-адреса, логины, сообщения об ошибках, JSON-тела запросов — всё это строки. В отличие от примитивов (int, double, boolean), String является полноценным классом в Java, поэтому его название пишется с заглавной буквы. Значение строки всегда заключается в двойные кавычки.

String baseUrl = "https://shop.example.com";
String errorMessage = "Неверный пароль";

Операции с данными: склеивание строк

Часто в тестах нужно собрать одни данные из других. Например, у вас есть базовый URL тестового стенда и конкретный путь к странице авторизации. В Java для объединения строк используется знак +. Этот процесс называется конкатенацией.

String baseUrl = "https://qa-env.mysite.com";
String endpoint = "/login";
String fullUrl = baseUrl + endpoint;
// Результат: "https://qa-env.mysite.com/login"

Если вы попытаетесь «сложить» строку и число, Java автоматически превратит число в текст и приклеит его к строке. Это невероятно удобно для формирования понятных логов выполнения теста.

Практика: сценарий проверки товара

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

public class ProductTest {
    public static void main(String[] args) {
        // Подготовка тестовых данных
        String productName = "Беспроводные наушники";
        double expectedPrice = 120.50;
        int rating = 5;
        boolean isAvailableInStock = true;

        // Формирование и вывод отчета о тесте
        System.out.println("Запуск теста для товара: " + productName);
        System.out.println("Ожидаемая цена: " + expectedPrice + " USD");
        System.out.println("Оценка пользователей: " + rating + " звезд");
        System.out.println("Товар в наличии: " + isAvailableInStock);
    }
}

Запустив этот код, вы получите аккуратный лог в консоли. Сейчас мы задали значения жестко в коде (захардкодили). В реальном фреймворке эти переменные будут заполняться автоматически: expectedPrice мы будем брать из базы данных, а фактическую цену — считывать с веб-страницы с помощью Selenium, после чего сравнивать их.

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

Управляющие конструкции: реализация логики проверок через условия и циклы

Управляющие конструкции: реализация логики проверок через условия и циклы

Представьте типичный ручной тест-кейс авторизации: «Если логин и пароль верны, убедиться, что открылся профиль пользователя; в противном случае проверить наличие сообщения об ошибке». В этой инструкции заложена логика принятия решений. До сих пор наши программы на Java были линейными — они выполняли команды сверху вниз, шаг за шагом. Но настоящий автотест должен уметь оценивать ситуацию, сравнивать ожидаемый результат с фактическим и реагировать на изменения.

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

Операторы сравнения: как программа задает вопросы

В прошлой главе мы сохраняли данные в переменные. Теперь мы будем их сравнивать. Результатом любого сравнения в Java всегда является значение типа boolean — то есть либо true (истина), либо false (ложь).

Для чисел и символов в Java используются математические операторы сравнения:

Оператор Значение Пример в коде Результат (если x=5x = 5)
==== Равно x == 5 true
≠\neq Не равно (в коде пишется как !=) x != 5 false
>> Больше x > 10 false
<< Меньше x < 10 true
≥\geq Больше или равно (в коде >=) x >= 5 true
≤\leq Меньше или равно (в коде <=) x <= 4 false

Главная ловушка для новичков: путаница между одинарным знаком == и двойным ====. Одинарный == — это присваивание (положить значение в переменную). Двойной ==== — это сравнение (проверить, равны ли значения).

Особенность сравнения текста (String)

Строки в Java — это ссылочный тип данных. Если мы попытаемся сравнить два текста через ====, программа проверит не сами буквы, а то, лежат ли они в одной и той же ячейке памяти. Для автотестов это почти всегда приводит к ложным ошибкам.

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

String expectedTitle = "Корзина";
String actualTitle = "Корзина";

// Правильное сравнение текста
boolean isTitleCorrect = actualTitle.equals(expectedTitle);
System.out.println(isTitleCorrect); // Выведет true

Ветвление: конструкция if / else

Получив логическое значение (true или false), программа должна выбрать путь дальнейшего выполнения. Это реализуется с помощью конструкции if (если) и else (иначе).

Это прямой аналог шага проверки (Assertion) в тестировании.

Посмотрим на синтаксис:

int statusCode = 404;

if (statusCode == 200) {
    // Этот блок выполнится, только если условие в круглых скобках true
    System.out.println("Тест пройден: страница загружена успешно.");
} else {
    // Этот блок выполнится во всех остальных случаях (false)
    System.out.println("Тест упал: получена ошибка " + statusCode);
}

Иногда сценарий требует больше двух вариантов развития событий. Например, HTTP-статусы делятся на информационные, успешные, редиректы, ошибки клиента и ошибки сервера. Для множественного выбора используется цепочка else if:

int responseTime = 1500; // время ответа сервера в миллисекундах

if (responseTime < 500) {
    System.out.println("Отличная производительность");
} else if (responseTime <= 2000) {
    System.out.println("Приемлемая производительность");
} else {
    System.out.println("Баг: сервер отвечает слишком долго");
}

Программа проверяет условия сверху вниз. Как только она находит первое истинное условие, она выполняет его блок кода и полностью выходит из всей конструкции if/else, игнорируя остальные проверки.

Циклы: автоматизация рутины

Вторая базовая потребность в автоматизации — повторение действий. Представьте, что вам нужно проверить наличие кнопки «Купить» у 100 товаров на странице. Писать 100 раз одну и ту же команду checkButton() бессмысленно.

Для многократного выполнения одного и того же блока кода используются циклы. Самый распространенный в автоматизации — цикл for.

Структура цикла for состоит из трех частей, разделенных точкой с запятой:

  1. Инициализация счетчика: с чего начинаем (например, int i = 1).
  2. Условие: до каких пор крутим цикл (например, i≤5i \leq 5).
  3. Шаг: как меняем счетчик после каждого круга. Чаще всего используют оператор инкремента ++, который увеличивает значение переменной ровно на 1 (i++i++ это сокращение от i=i+1i = i + 1).
// Выполнить действие 3 раза
for (int i = 1; i <= 3; i++) {
    System.out.println("Попытка подключения номер: " + i);
}

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

Рассмотрим синтетический пример. Допустим, мы ищем нужный товар на страницах каталога. Мы готовы пролистать максимум 5 страниц.

int targetPage = 3; // Товар, который мы ищем, находится на 3-й странице

for (int page = 1; page <= 5; page++) {
    System.out.println("Открыта страница " + page);

    if (page == targetPage) {
        System.out.println("Товар найден! Останавливаем поиск.");
        break; // Команда break немедленно прерывает выполнение всего цикла
    }
}

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

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