Паттерны автоматизации и архитектура автотестов

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

  1. Page Object Pattern (Паттерн Объекта Страницы)

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

  2. Data Generation Pattern (Паттерн генерации данных)

    К этому паттерну относится:

    2.1. Классический Data-Driven Testing (Тестирование на Основе Данных) паттерн, который позволяет запускать один и тот же тест с разными наборами данных для проверки различных сценариев.

    2.2. Я также отношу к нему создание отдельных классов или библиотек, которые автоматически генерирует тестовые данные для тестов (рандомные и/или кастомные).

  3. Steps Pattern

    Этот паттерн отвечает за создания слоя бизнес-логики. Это паттерн проектирования автоматизированных тестов или автоматизации действий, когда тестовый сценарий разбивается на отдельные шаги (steps) или этапы для удобства выполнения и поддержки. Чаще всего каждый шаг описывает какое-то бизнес действие системы. Такое как: «Пользователь_вошел_в_систему», «Пользователь_сделал_заказ» и прочие.

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

    В этот паттерн я включаю:

    3.1. Классический Behavior-Driven Development (BDD) Pattern — о нем можно почитать самостоятельно.

    3.2. Любой другой код суть которого описать поведение пользователя в отдельных блоках / шагах / методами / ключевых словах.

  4. Паттерн проверок (Assert/Checker)

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

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

  5. Паттерн логирования

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

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

Но возникает вопрос: как же эти паттерны работают вместе и образую одну единую архитектруру?

Для себя я выделила следующую структуру- есть три слоя или контекстных области, которые взаимодействуют друг с другом:

a4645f62a3deccd150158fd52bdb26b0.png

  • Контекстная область взаимодействия с приложением, которое мы тестируем. Я называю ее ядром (Core).

  • Контекстная область тестов (Tests).

  • Контекстная область раннера автотестов (Runner).

Первый слой — это ядро, в котором находятся материалы, связанные с описанием нашего приложения и взаимодействием нашего кода с ним. Он содержит методы, которые вызывают API, методы. Они в свою очередь взаимодействуют с базой данных, методы, которые описывают архитектуру веб страниц с локаторами. Тут описывается все, что связано с контекстом приложения. Сюда относится паттерн Page Object Pattern.

Второй слой — тестовый слой. Сюда относится всё, что связано с автотестами, включая всё необходимое для запуска тестов (пред настройки), создания тестовых данных для тестов и проверок, которые происходят в тесте. Я называю этот слой — контекстом автотестов. Сюда относятся паттерн шагов, паттерн проверок и паттерн данных.

Третий слой — это слой раннера автотестов. Сюда относится паттерн логирования и всё, что связано с запуском тестов в определенной среде (предварительные настройки, последующие настройки).

Расскажу чуть подробнее про каждый слой:

1. Контекстная область взаимодействия с приложением

1a13c73324a33c2fd6a953a0c74c8b91.png

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

1.Блок Page Object — это шаблон проектирования для автоматизации тестирования веб-приложений. Он предполагает создание объектно-ориентированных моделей страниц вашего веб-приложения, которые отражают функциональность и элементы интерфейса страниц.

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

Кратко говоря, Page Object позволяет абстрагировать веб-страницы в объекты, делая код тестов более читаемым, модульным и легким в поддержке.

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

  • Отправка запросов: позволяют через API получить данные или взаимодействовать с данными на сервере.

  • Перехват запросов: некоторые API методы также могут предоставлять возможность перехвата или обработки запросов, которые поступают к приложению. Это может быть полезным для моканья ответа с сервера.

3.Блок BD методы — предоставляет собой инструмент взаимодействия в базой данных из кода.

Основные аспекты этих блоков включают:

  1. Модульность и виртуальные границы: Каждый блок представляет собой отдельный компонент с четко определенными функциями. Они не зависят друг от друга и выполняют свою задачу независимо. К примеру, если вам нужен метод, который проверит, что вся страница «Заказы» загрузилась корректно т.е. метод. который визуально просмотрит страницу на предмет отображения элементов и проверит, что API запрос пришел со статусом 200, тогда вам нужно для этого создать тестовый шаг.

    Этот шаг будет описан в слое Tests в блоке Steps. Его можно назвать User_check_opders_page. Он будет включать в себя переход на страницу через pageOpject order класс этой страницы, проверка видимости элементов страницы, а также в в этом шаге будет проверка на то, что API запрос о получение данных всех заказов вернулся со статусом 200.

  2. Использование настроек: Настройки для вызова методов, такие как конфигурации базы данных, доменные URL страниц для Page Object, и URL для API, хранятся в слое runner. Это упрощает изменение конфигурации без изменения кода.

2. Контекстная область тестовых сценариев

Концепция второго слоя, тестового слоя, включает в себя все аспекты автотестов. Она включает в себя несколько ключевых компонентов:

  1. Файлы автотестов: это сценарии, тест- кейсы или файлы, в которых описаны автотесты.

  2. Блок генерации тестовых данных: эти методы используются для создания данных, необходимых для проведения тестов. Обычно эти методы вызываются в начале теста для подготовки данных прогона тестов.

  3. Тестовые шаги (Steps): они представляют собой методы, которые описывают последовательность действий, выполняемых пользователем в приложении. Эти шаги выполняются в тесте. Эти методы как раз таки используют методы из первого слоя (например, методы Page Object) для взаимодействия с тестируемой системой.

  4. Проверки состояния системы (Check): после выполнения тестовых шагов идут проверки для подтверждения, что система находится в ожидаемом состоянии. Эти проверки сравнивают фактическое состояние системы с ожидаемым результатом. Они также проверяют состояние системы на соответствие ожиданиям.

На диаграмме ниже показаны то, как блоки вызывают друг друга.

1fe5681e8c142184e55ed31244d73b01.png

Реальный тест включает в себя следующий ход:

2b4e94f690d13c15536770f3f2faf4d7.png

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

Получаем следующий тестовый путь:

  • Подготовка тестовых данных

  • Выполнение шагов взаимодействия с системой

  • Проверка состояния системы

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

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

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

3. Контекстная область запуска автотестов

44183fcd4c5170959f10988de57c005a.png

Кратко расскажу о содержании этого слоя. Он включает в себя настройку окружения, логирование и создание скриншотов во время выполнения автотестов, создание репортов и отправку репортов в различные каналы. Кроме того, сюда входят глобальные хуки «before» и «after», где осуществляются глобальные настройки, передача переменных окружения, предварительная и завершающая настройка приложения. Важно отметить, что эти блоки также независимы друг от друга и связаны (вызываются) исключительно с тестовым слоем. То есть, имеют свои виртуальные границы. Отдельно настройки окружения, отдельно логирование, отдельно создание репорта и отправка.

4. Как между собой взаимодействуют слои


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

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

16ee0ace9d32c540e2ba56014d84a11d.png

5. Общая картина нашей структуры и взаимодействия

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

9059fad4d21c73578e5a51f3a8c3722f.png

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

Подводя итог всего написаного выше: выносите контексты в отдельные модули и соблюдайте виртуальные границы)))

Спасибо за внимание!

© Habrahabr.ru