Рефакторинг старых тестов

Рефакторинг старых тестов является неотъемлемой частью поддерживаемого и масштабируемого автоматизированного тестирования. В Protractor, учитывая его тесную интеграцию с Angular и асинхронной моделью работы WebDriver, процесс обновления и улучшения тестов требует особого внимания к структуре, синхронизации и читаемости кода.


Основные причины необходимости рефакторинга

  1. Устаревшие селекторы Элементы страницы со временем изменяются, и тесты начинают ломаться. Использование надежных стратегий поиска, таких как by.css, by.id или кастомные by.xpath, позволяет уменьшить хрупкость тестов.

  2. Сложные и длинные сценарии Тесты, в которых проверяется несколько функциональностей сразу, трудно поддерживать. Их следует разбивать на маленькие, логически изолированные тесты.

  3. Повторяющийся код Общие операции, такие как логин или переход на определенную страницу, лучше выносить в функции или Page Object, чтобы избежать дублирования.

  4. Проблемы с асинхронностью Использование старых методов синхронизации, таких как browser.sleep(), делает тесты нестабильными. Следует переходить на ожидания через ExpectedConditions или встроенные возможности Protractor для ожидания элементов.


Принципы рефакторинга

1. Использование Page Object Model (POM) Каждая страница приложения должна иметь соответствующий объект с методами для взаимодействия и получения данных. Пример:

class LoginPage {
    constructor() {
        this.usernameInput = element(by.id('username'));
        this.passwordInput = element(by.id('password'));
        this.loginButton = element(by.buttonText('Login'));
    }

    async login(username, password) {
        await this.usernameInput.sendKeys(username);
        await this.passwordInput.sendKeys(password);
        await this.loginButton.click();
    }
}

module.exports = new LoginPage();

Преимущества:

  • Легче обновлять селекторы при изменении UI.
  • Повышается читаемость тестов.
  • Снижается дублирование кода.

2. Асинхронное управление ожиданиями Protractor работает на основе Promises и асинхронной модели. Использование async/await делает тесты более предсказуемыми и читаемыми:

const EC = protractor.ExpectedConditions;

await browser.wait(EC.visibilityOf(element(by.id('dashboard'))), 5000);

Избегание browser.sleep() значительно повышает стабильность тестов и уменьшает время выполнения.


3. Стандартизация селекторов Следует использовать единый стиль выбора элементов по всему проекту. Рекомендуется:

  • by.id для уникальных идентификаторов.
  • by.css для сложных комбинаций классов и атрибутов.
  • by.model или by.binding для Angular-приложений.

Пример:

element(by.css('.nav-menu .active')).getText();

4. Разделение данных и логики теста Тестовые данные лучше хранить отдельно — в JSON или JavaScript-объектах. Это упрощает поддержку и позволяет быстро менять данные без редактирования кода:

const testData = require('../data/loginData.json');

await loginPage.login(testData.validUser.username, testData.validUser.password);

5. Упрощение проверок и ожиданий Старые тесты часто содержат сложные цепочки ожиданий. Их можно заменить компактными методами:

await expect(element(by.css('.alert-success')).getText())
    .toEqual('Login successful');

Использование expect совместно с async/await делает проверки более надежными.


Этапы рефакторинга

  1. Анализ существующих тестов

    • Определение повторяющихся блоков.
    • Выявление «устаревших» селекторов и browser.sleep().
  2. Выделение Page Objects

    • Создание отдельных файлов для каждой страницы.
    • Перенос методов взаимодействия и получения данных.
  3. Оптимизация ожиданий

    • Замена статических задержек на ExpectedConditions.
    • Проверка стабильности тестов после изменений.
  4. Удаление дублирования и стандартизация

    • Унификация селекторов и тестовых данных.
    • Использование общих утилит и хелперов.
  5. Проверка и корректировка тестовых сценариев

    • Разделение слишком длинных тестов на логически независимые.
    • Удаление ненужных проверок и повторов.

Практические рекомендации

  • Все Page Objects должны быть компактными и содержать только методы, связанные с конкретной страницей.
  • Названия методов должны отражать действие, например: clickSubmitButton(), enterUsername().
  • Любые данные, которые могут измениться (например, тексты сообщений), лучше хранить отдельно.
  • Асинхронность должна быть полностью контролируемой через async/await, без смешивания с колбэками.

Рефакторинг старых тестов в Protractor не только повышает их стабильность и читаемость, но и упрощает дальнейшее расширение автотестов, что критически важно для крупных проектов с частыми изменениями интерфейса.