THREADQA
    THREADQA
    Главная
    Курсы
    Java QA AutomationNEW
    Новый курс · уже можно купить
    Python QA Automation
    Pytest, Playwright, Docker
    iOS QA Automation
    XCTest, XCUITest, Fastlane
    Все курсы
    Практика
    Мок собеседование
    Тренировка перед реальным интервью
    Записи собеседований
    Разбор реальных собеседований
    Буткемп
    Интенсивная подготовка к работе
    XPath Practice Hub
    Тренажёр XPath-запросов
    Roadmap
    Путь QA-инженера
    XPath Dinner
    Практика XPath в игровом формате
    Блог
    FAQ
    Для компаний
    1. Домой
    2. Обучение
    3. Топ-10 ошибок в автотестах на Java которые я вижу каждую неделю
    Все статьи
    Обучение
    27 апреля 2026 г. 14 мин чтения

    Топ-10 ошибок в автотестах на Java которые я вижу каждую неделю

    Tech Lead из Ozon и VK разбирает 10 самых частых ошибок в Java-автотестах: отсутствие архитектуры, кривые локаторы, слабое знание языка, устаревший стек, игнорирование JUnit Extensions и нейросетей. С примерами кода как делать правильно.

    Олег Пендрак
    Олег Пендрак
    Tech Lead QA Automation · Ozon, VK

    Топ-10 ошибок в автотестах на Java которые я вижу каждую неделю

    Я провожу code review автотестов каждую неделю — в рамках менторства, на мок-собеседованиях и в командах где работаю. За несколько лет сложился устойчивый список ошибок которые встречаются снова и снова, независимо от компании и уровня специалиста. Некоторые из них делают даже Middle-инженеры с 2–3 годами опыта.

    Это не теория из учебника. Это реальные проблемы из реальных проектов. Разберём каждую с примером как делают и как надо.


    Ошибка #1: Нет архитектуры — нельзя переиспользовать компоненты

    Самая распространённая и самая дорогостоящая ошибка. Тесты написаны как набор независимых скриптов: каждый тест сам открывает браузер, сам находит элементы, сам делает всё с нуля. Когда меняется один элемент на странице — нужно обновлять 40 тестов вместо одного.

    Как делают неправильно:

    java
    1// Плохо: логика дублируется в каждом тесте
    2@Test
    3void testCheckout() {
    4    open("https://shop.example.com/login");
    5    $("#email").setValue("user@test.com");
    6    $("#password").setValue("pass123");
    7    $("button[type=submit]").click();
    8    // ... 30 строк логики покупки
    9}
    10
    11@Test
    12void testOrderHistory() {
    13    open("https://shop.example.com/login");
    14    $("#email").setValue("user@test.com");  // дублирование
    15    $("#password").setValue("pass123");     // дублирование
    16    $("button[type=submit]").click();        // дублирование
    17}

    Как надо — Page Object Model + степы:

    java
    1// Хорошо: логика в одном месте, тесты читаемые
    2public class LoginPage {
    3    private final SelenideElement email    = $("#email");
    4    private final SelenideElement password = $("#password");
    5    private final SelenideElement submit   = $("button[type=submit]");
    6
    7    public MainPage loginAs(String email, String password) {
    8        this.email.setValue(email);
    9        this.password.setValue(password);
    10        submit.click();
    11        return new MainPage();
    12    }
    13}
    14
    15@Test
    16void testCheckout() {
    17    new LoginPage().loginAs("user@test.com", "pass123")
    18        .goToCart()
    19        .checkout();
    20}

    Правило простое: если одно и то же действие встречается в двух тестах — оно должно быть в Page Object или степе. Не в тесте.


    Ошибка #2: Кривые локаторы

    Хрупкие локаторы — вторая по частоте причина нестабильных тестов. Тест падает не потому что сломалась функциональность, а потому что разработчик переименовал CSS-класс или изменил структуру DOM.

    java
    1// Плохо: хрупкие локаторы
    2$("div.sc-bdXxxt.fKBQlc > span:nth-child(2)").click();  // XPath по структуре
    3$(".btn-primary-large-rounded-shadow").click();          // CSS по визуальному классу
    4$("//div[3]/button[1]").click();                         // XPath по позиции
    5
    6// Хорошо: стабильные локаторы
    7$("[data-testid='submit-button']").click();   // атрибут для тестов
    8$("[data-qa='login-form']").click();          // явный QA-атрибут
    9$(byText("Оформить заказ")).click();           // по тексту (если текст стабилен)
    10$("#checkout-submit").click();                // по ID

    Иерархия надёжности локаторов (от лучшего к худшему): data-testid / data-qa → ID → aria-label → текст → CSS по семантическому классу → XPath по структуре. Если в проекте нет data-testid — договоритесь с разработчиками добавить их. Это занимает 10 минут и экономит часы отладки.


    Ошибка #3: Слабое знание Java

    QA-инженеры часто учат Java ровно настолько чтобы написать тест. Это работает до первого code review. Потом выясняется что человек не знает generics, не понимает разницу между equals() и ==, не умеет работать со Stream API и пишет циклы там где нужна одна строка.

    java
    1// Плохо: не знает Stream API
    2List<String> activeUsers = new ArrayList<>();
    3for (User user : users) {
    4    if (user.isActive()) {
    5        activeUsers.add(user.getEmail());
    6    }
    7}
    8
    9// Хорошо: Stream API
    10List<String> activeUsers = users.stream()
    11    .filter(User::isActive)
    12    .map(User::getEmail)
    13    .toList();
    14
    15// Плохо: сравнение строк через ==
    16if (status == "ACTIVE") { ... }
    17
    18// Хорошо: null-safe сравнение
    19if (Objects.equals(status, "ACTIVE")) { ... }

    Минимум который должен знать Java QA Automation инженер: ООП (наследование, интерфейсы, абстрактные классы), generics, коллекции (List, Map, Set), Stream API, Optional, лямбды, исключения. Без этого код будет работать, но его будет стыдно показывать на собеседовании.


    Ошибка #4: Устаревший стек

    В 2026 году я всё ещё вижу проекты на JUnit 4, Selenium 3, TestNG без причины. Это не просто эстетическая проблема — старый стек медленнее, менее функционален и создаёт проблемы при найме.

    УстарелоАктуально в 2026Почему менять
    JUnit 4JUnit 5Extensions, параметризация, вложенные тесты
    Selenium 3 + явные ожиданияSelenide 7 / PlaywrightАвтоожидания, читаемость, скорость
    TestNG (без причины)JUnit 5Лучшая экосистема, активная разработка
    RestTemplate в тестахREST Assured 5+Специализированный инструмент для API
    Allure 2.xAllure 3 / Allure TestOpsИнтеграция с CI, история запусков
    Jenkins (legacy)GitLab CI / GitHub ActionsДекларативные пайплайны, проще поддержка

    Переход с JUnit 4 на JUnit 5 занимает день. Переход с Selenium на Selenide — неделю. Это инвестиция которая окупается за месяц.


    Ошибка #5: Повторяющиеся тесты без параметризации

    Классика: три теста которые делают одно и то же с разными данными. Вместо одного параметризованного теста — три копии с разными значениями в коде.

    java
    1// Плохо: три одинаковых теста
    2@Test void loginWithGmail()     { loginPage.loginAs("user@gmail.com",   "pass"); }
    3@Test void loginWithCorporate() { loginPage.loginAs("user@company.ru",  "pass"); }
    4@Test void loginWithSubdomain() { loginPage.loginAs("u@mail.example.com","pass"); }
    5
    6// Хорошо: @ParameterizedTest
    7@ParameterizedTest
    8@ValueSource(strings = {"user@gmail.com", "user@company.ru", "u@mail.example.com"})
    9void loginWithValidEmail(String email) {
    10    loginPage.loginAs(email, "pass");
    11    assertThat(mainPage.isLoaded()).isTrue();
    12}
    13
    14// Для сложных данных — @MethodSource
    15@ParameterizedTest
    16@MethodSource("validCredentials")
    17void loginWithValidCredentials(String email, String password, String expectedRole) {
    18    loginPage.loginAs(email, password);
    19    assertThat(userProfile.getRole()).isEqualTo(expectedRole);
    20}
    21
    22static Stream<Arguments> validCredentials() {
    23    return Stream.of(
    24        Arguments.of("admin@test.com",  "admin123",  "ADMIN"),
    25        Arguments.of("user@test.com",   "user123",   "USER"),
    26        Arguments.of("mentor@test.com", "mentor123", "MENTOR")
    27    );
    28}

    Ошибка #6: Не используют JUnit 5 Extensions

    JUnit 5 Extensions — один из самых мощных инструментов фреймворка. Они позволяют вынести повторяющуюся логику (setup/teardown, логирование, скриншоты, управление браузером) в одно место. Большинство QA-инженеров знают только @BeforeEach и @AfterEach и не подозревают о существовании Extensions.

    java
    1// Хорошо: Extension для автоматических скриншотов при падении
    2public class ScreenshotExtension implements TestWatcher {
    3    @Override
    4    public void testFailed(ExtensionContext context, Throwable cause) {
    5        String name = context.getDisplayName();
    6        Selenide.screenshot("screenshots/" + name);
    7        Allure.addAttachment("Screenshot", new FileInputStream("screenshots/" + name + ".png"));
    8    }
    9}
    10
    11// Хорошо: Extension для управления браузером
    12public class BrowserExtension implements BeforeEachCallback, AfterEachCallback {
    13    @Override
    14    public void beforeEach(ExtensionContext ctx) {
    15        Configuration.browser = "chrome";
    16        Configuration.headless = true;
    17        Configuration.baseUrl = System.getProperty("base.url", "https://app.example.com");
    18    }
    19    @Override
    20    public void afterEach(ExtensionContext ctx) { closeWebDriver(); }
    21}
    22
    23// Использование — чистые тесты без setup/teardown
    24@ExtendWith({BrowserExtension.class, ScreenshotExtension.class})
    25class LoginTests {
    26    @Test
    27    void loginTest() { /* только бизнес-логика */ }
    28}

    Другие полезные Extension: ParameterResolver для инжекции зависимостей в тесты, ExecutionCondition для условного запуска, @RegisterExtension для динамической регистрации.


    Ошибка #7: Thread.sleep() вместо ожиданий

    Thread.sleep() — признак того что инженер не понимает как работает асинхронность в браузере. Тест либо ждёт слишком долго (медленный), либо недостаточно (нестабильный).

    java
    1// Плохо
    2$("#submit").click();
    3Thread.sleep(3000);  // ждём 3 секунды вслепую
    4$("#success").shouldBe(visible);
    5
    6// Хорошо: Selenide ждёт автоматически (до 4 сек по умолчанию)
    7$("#submit").click();
    8$("#success").shouldBe(visible);
    9
    10// Хорошо: кастомное время ожидания если нужно
    11$("#heavy-report").shouldBe(visible, Duration.ofSeconds(30));
    12
    13// Хорошо: для чистого Selenium — WebDriverWait
    14new WebDriverWait(driver, Duration.ofSeconds(10))
    15    .until(ExpectedConditions.visibilityOfElementLocated(By.id("success")));

    Ошибка #8: Игнорирование нейросетей в работе

    В 2026 году QA-инженер который не использует AI-инструменты работает в 2–3 раза медленнее конкурентов. Нейросети не заменяют инженера — они убирают рутину.

    • ▸Генерация тестовых данных: попросите ChatGPT/Claude сгенерировать 50 вариантов невалидных email-адресов для негативных тестов — 10 секунд вместо 10 минут
    • ▸Boilerplate-код: Page Object для новой страницы, POJO-классы для API-ответов, конфигурационные классы — генерируется за секунды
    • ▸Анализ упавших тестов: вставьте стектрейс в Claude и получите объяснение причины и варианты исправления
    • ▸Рефакторинг: попросите улучшить читаемость метода или предложить более идиоматичный Java-код
    • ▸Граничные случаи: опишите функциональность и получите список edge cases которые вы могли пропустить

    Главное правило: AI генерирует черновик, инженер проверяет и дорабатывает. Слепо копировать код из ChatGPT — такая же ошибка как не использовать его вообще.


    Ошибка #9: Тесты зависят друг от друга

    Тест B падает потому что тест A не создал нужные данные. Или тест C проходит только если запускать после теста B. Это делает тест-сьют хрупким: нельзя запустить один тест, нельзя запустить в параллель, нельзя изменить порядок.

    java
    1// Плохо: тест зависит от состояния после предыдущего
    2@Test @Order(1)
    3void createUser() { /* создаёт пользователя в БД */ }
    4
    5@Test @Order(2)
    6void updateUser() { /* упадёт если createUser не запускался */ }
    7
    8// Хорошо: каждый тест самодостаточен
    9@Test
    10void updateUser() {
    11    // создаём данные прямо здесь через API
    12    User user = userApi.create(UserFactory.defaultUser());
    13    userApi.update(user.getId(), UpdateRequest.builder().name("New Name").build());
    14    assertThat(userApi.get(user.getId()).getName()).isEqualTo("New Name");
    15}

    @Order в JUnit 5 существует для специфичных сценариев — не для компенсации зависимостей между тестами. Каждый тест должен сам создавать нужные данные и сам убирать за собой.


    Ошибка #10: Нет разделения на слои (UI / API / DB)

    Зрелый тест-фреймворк использует разные слои для разных задач. Когда всё делается через UI — тесты медленные и хрупкие.

    java
    1// Плохо: всё через UI, включая подготовку данных (5 минут на тест)
    2@Test
    3void testOrderHistory() {
    4    loginPage.loginAs("user", "pass");
    5    catalogPage.open().addToCart("Product A");
    6    cartPage.checkout().fillAddress(address).pay();
    7    orderHistoryPage.open().assertOrderExists("Product A");
    8}
    9
    10// Хорошо: подготовка через API, UI только для проверки отображения (30 секунд)
    11@Test
    12void testOrderHistory() {
    13    String token = authApi.login("user", "pass");
    14    Order order  = orderApi.create(token, OrderRequest.of("Product A"));
    15
    16    open("/orders");
    17    $("[data-testid='order-" + order.getId() + "']").shouldBe(visible);
    18}

    Правило: используй самый быстрый и надёжный способ для каждой задачи. Создание данных — API или DB. Проверка бизнес-логики — API. Проверка отображения — UI. Это пирамида тестирования, и она работает.


    Итого: чеклист перед code review

    • Есть Page Object Model

      логика не дублируется в тестах

    • Локаторы используют data-testid / data-qa / ID

      не XPath по структуре

    • Код использует Stream API, Optional, лямбды

      не for-циклы везде

    • Стек актуальный: JUnit 5, Selenide 7+, REST Assured 5+
    • Повторяющиеся тесты заменены на @ParameterizedTest
    • Общая логика вынесена в JUnit 5 Extensions
    • Нет Thread.sleep()

      только автоожидания Selenide или WebDriverWait

    • AI использовался для генерации boilerplate и тестовых данных
    • Каждый тест самодостаточен

      не зависит от других тестов

    • Подготовка данных через API/DB

      UI только для проверки отображения

    Хочешь писать автотесты без этих ошибок с первого дня?

    В обновлённом курсе Java QA Automation от ThreadQA все эти практики собраны в единую программу: Java 21, Page Object Model, JUnit 5 Extensions, REST Assured, Selenide, Kafka и работа с AI. Около 60 часов контента, практика на реальном backend-проекте ShawarmaShop и бесплатный урок-превью. Продажи открыты: курс можно купить сейчас за 65 000 ₽ с полной оплатой или оплатой частями через доступных партнёров СБП.

    #ошибки в автотестах java#java qa automation ошибки#code review автотесты#page object model java#junit 5 extensions#локаторы selenium#параметризованные тесты junit#архитектура автотестов#java qa automation best practices#автоматизация тестирования java советы

    Хочешь практиковаться, а не только читать?

    Курсы по Java, Python и iOS автоматизации. Первые уроки бесплатно.

    Начать бесплатно

    Читайте также

    Обучение
    9 мин

    Playwright vs Selenium в 2026: что выбрать для автоматизации тестирования

    Честное сравнение Playwright и Selenium в 2026 году: скорость, поддержка браузеров, синтаксис, популярность. Когда использовать Playwright, а когда Selenium.

    Обучение
    18 мин

    REST Assured: полное руководство по тестированию API на Java

    Изучаем REST Assured для автоматизации API тестирования: установка, базовые запросы, валидация JSON, аутентификация, десериализация в классы, спецификации и практические паттерны.

    Обучение
    22 мин

    Postman для тестировщика: как тестировать REST API с нуля

    Практический гайд по Postman для Manual QA: запросы, headers, body, авторизация, негативные проверки и переход к REST Assured на Java.

    Все статьи блога

    Содержание

    Топ-10 ошибок в автотестах на Java которые я вижу каждую неделюОшибка #1: Нет архитектуры — нельзя переиспользовать компонентыОшибка #2: Кривые локаторыОшибка #3: Слабое знание JavaОшибка #4: Устаревший стекОшибка #5: Повторяющиеся тесты без параметризацииОшибка #6: Не используют JUnit 5 ExtensionsОшибка #7: Thread.sleep() вместо ожиданийОшибка #8: Игнорирование нейросетей в работеОшибка #9: Тесты зависят друг от другаОшибка #10: Нет разделения на слои (UI / API / DB)Итого: чеклист перед code reviewХочешь писать автотесты без этих ошибок с первого дня?

    Автор

    Олег Пендрак
    Олег Пендрак
    Tech Lead QA

    Опыт в Ozon и VK. YouTube-канал 10к+ подписчиков.

    Готов к практике?

    Первые уроки бесплатно

    Начать бесплатно
    THREADQAПлатформа QA Automation

    О платформе

    Обучаем автоматизации тестирования на Java, Python и iOS. Курсы, мок-интервью, буткемп с менторством до оффера.

    Онлайн 24/7

    Курсы

    • Java QA AutomationNEW
    • Python QA Automation
    • iOS QA Automation
    • Про ThreadQA

    Услуги

    • QA Буткемп
    • Мок-собеседования
    • Записи собеседований

    Инструменты

    • Roadmap QA
    • Тренажёр XPath
    • XPath Diner

    Контакты

    • Email
      info@threadqa.ru
    • Telegram
      @penolegrus
    Публичная офертаПолитика конфиденциальностиУсловия использования
    © 2026·ThreadQA LMS·Все права защищены