Хабрахабр

Реализация паттерна Page Object на Python + pytest

Штудируя интернет, нашел реализацию на других языках и фреймворках: обучающие статьи, которые были непонятны для меня. Когда я начинал изучать автоматизацию тестирования, не мог понять — “что такое Page Object и как его реализовать на Python + pytest?”. Идея — показать реализацию на Python + pytest и объяснить ее доступным языком. Поэтому решил написать этот разбор.

Что такое Page Object

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

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

Page Object определяет в себе части:

  • Base Page \ Base Class — Реализует в себе необходимые методы для работы с webdriver.
  • Page Object \ Page Class — Реализует методы для работы с элементами на веб-страницах.
  • Tests — Реализует тесты, описанные бизнес-логикой тест-кейса.

Схема паттерна Page Object.
image
Чтобы наглядно объяснить тему, реализуем автоматизированный тест.

Теоретическая часть реализации

Шаги:

  1. Пользователь открывает браузер;
  2. Пользователь вводит в адресную строку https://ya.ru/;
  3. Пользователь вводит слово “Hello” в строку поиска;
  4. Пользователь нажимает кнопку “Найти”.

Выдача поиска имеет подпункты (видео, картинки и тд.). Ожидаемый результат:
Пользователь перенаправлен на выдачу поиска.

Проверка: на странице поиска присутствует бар навигации и элементы “картинки” и “видео”.

Практическая часть реализации

Для понимания статьи необходимо знать базовые конструкции Python, ООП, понимать принципы и функции Selenium.

Установить их можно через пакетный менеджер pip. Будем использовать библиотеки: selenium и pytest.

pip install selenium
pip install pytest

В статье используется chrome webdriver. Так же не забываем скачать драйвер для браузера. Для работы с ним положите файл в корневой каталог проекта. Скачать его можно по ссылке.

Создаем фикстуру

Описывать её будем в фикстуре. Для начала необходимо реализовать инициализацию для WebDriver. С помощью фикстуры, можно подготовить начальное состояние системы для проведения тестирования. Фикстуры в pytest — функции которые имеют свою периодичность выполнения.
Это альтернативная замена SetUp и TearDown методов в unittest.

В pytest есть зарезервированное имя для файла с фикстурами — conftest.py.

Создаем файл conftest.py и реализуем функцию c именем — browser.

Это означает что данная функция-фикстура будет исполнятся только 1 раз за тестовую сессию. Помечаем ее декоратором @pytest.fixture и передаем параметр scope со значением session.

import pytest
from selenium import webdriver @pytest.fixture(scope="session")
def browser(): driver = webdriver.Chrome(executable_path="./chromedriver") yield driver driver.quit()

В ней происходит инициализация webdriver с указанием где располагается chromedriver. Далее мы описываем часть, которая будет выполнятся перед тестами. Далее используем конструкцию yield, которая разделяет функцию на часть — до тестов и после тестов.

В части “после тестов” мы вызываем функцию quit, которая завершает сессию и убивает экземпляр webdriver.

Base Page

В классе BasePage определяем базовые методы для работы с WebDriver. Создаем файл BaseApp.py.

from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC class BasePage: def __init__(self, driver): self.driver = driver self.base_url = "https://ya.ru/" def find_element(self, locator,time=10): return WebDriverWait(self.driver,time).until(EC.presence_of_element_located(locator), message=f"Can't find element by locator ") def find_elements(self, locator,time=10): return WebDriverWait(self.driver,time).until(EC.presence_of_all_elements_located(locator), message=f"Can't find elements by locator {locator}") def go_to_site(self): return self.driver.get(self.base_url)

Указываем base_url, который будет использоваться для открытия страницы. В классе BasePage создаем конструктор, который принимает driver — экземпляр webdriver.

Далее создаем методы find_element (ищет один элемент и возвращает его) и find_elements (ищет множество и возвращает в виде списка).

Это обертка над WebdriverWait, который отвечает за явные ожидания в Selenium.

Это время для поиска элемента. В функции определяем время, которое по умолчанию равно 10-и секундам. Метод позволяет перейти на указываемую страницу. Метод go_to_site — вызывает функцию get из WebDriver. Передаем в него base_url.

Page object

Наш класс для веб-страницы реализуется в файле YandexPages.py

from BaseApp import BasePage
from selenium.webdriver.common.by import By class YandexSeacrhLocators: LOCATOR_YANDEX_SEARCH_FIELD = (By.ID, "text") LOCATOR_YANDEX_SEARCH_BUTTON = (By.CLASS_NAME, "search2__button") LOCATOR_YANDEX_NAVIGATION_BAR = (By.CSS_SELECTOR, ".service__name") class SearchHelper(BasePage): def enter_word(self, word): search_field = self.find_element(YandexSeacrhLocators.LOCATOR_YANDEX_SEARCH_FIELD) search_field.click() search_field.send_keys(word) return search_field def click_on_the_search_button(self): return self.find_element(YandexSeacrhLocators.LOCATOR_YANDEX_SEARCH_BUTTON,time=2).click() def check_navigation_bar(self): all_list = self.find_elements(YandexSeacrhLocators.LOCATOR_YANDEX_NAVIGATION_BAR,time=2) nav_bar_menu = [x.text for x in all_list if len(x.text) > 0] return nav_bar_menu

Он будет только для хранения локаторов.
В классе описываем локаторы: Создаем класс YandexSeacrhLocators.

LOCATOR_YANDEX_SEARCH_FIELD — локатор поисковой строки
LOCATOR_YANDEX_SEARCH_BUTTON — локатор кнопки “Найти”
LOCATOR_YANDEX_NAVIGATION_BAR — локатор бара навигации (Картинки, Видео и т.д.)

Создаем класс SearchHelper, наследуемся от BasePage.

Создает список и фильтрует по условию. Реализуем вспомогательные методы для работы с поиском:
enter_word — ищет элемент строки поиска, кликает и вводит в поиск необходимое слово;
click_on_the_search_button — ищет элемент кнопки поиска и кликает на неё;
check_navigation_bar — ищет элементы навигации и получает атрибут text. Для примера, переопределим время по умолчанию установив его — 2 сек. Если длина строки больше нуля, то добавляет элемент к списку.

Tests

from YandexPages import SearchHelper def test_yandex_search(browser): yandex_main_page = SearchHelper(browser) yandex_main_page.go_to_site() yandex_main_page.enter_word("Hello") yandex_main_page.click_on_the_search_button() elements = yandex_main_page.check_navigation_bar() assert "Картинки" and "Видео" in elements

Далее первой строчкой создаем объект страницы — yandex_main_page. Создаем тестовую функцию test_yandex_seacrh, которая будет принимать фикстуру browser. В функции описывается верхнеуровневая логика действий пользователя. Из объекта вызываем методы взаимодействия с элементами страницы.

Переименуем блоки под название файлов из статьи. Перенесем все что реализовали на схему, аналогично схеме Page Object.

image

Как видите, нам удалось реализовать паттерн на практике.

Спасибо за прочтение! Оставлю ссылку на готовый репозиторий.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»