Файл: Шпаргалка Page Object Model Паттерны проектирования.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 09.11.2023
Просмотров: 57
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
Шпаргалка: Page Object Model
1
Шпаргалка: Page Object Model
Паттерны проектирования
Можно писать код по особым правилам: так, чтобы с ним было удобно работать. Эти правила называют паттернами проектирования.
Например, разработчики изменили дизайн и класс кнопки. Обычно пришлось бы исправлять все тесты, в которых нужно её нажать. Изменения будет проще внести, если писать код по паттернам
Есть много разных паттернов — у всех свои названия. Один из них — Page Object Model, или POM.
Page Object Model
Он работает так: каждой странице приложения соответствует класс. Веб-элементы становятся полями этого класса, а действия с ними — методами.
Чем это поможет
Page Object Model используют, чтобы упростить работу с кодом тестов. Паттерн помогает отделить технические детали тест-кода от его логики. Так код становится более читаемым.
Вот клик по кнопке «Войти» без POM:
driver.findElement(By.className("auth-form__button")).click();
Клик по этой же кнопке, если использовать POM:
//objLoginPage — объект класса Page Object страницы авторизации objLoginPage.clickSignInButton();
Не только читать, но и редактировать код становится проще. Локаторы, которые относятся к странице, находятся в одном классе — page object. Если у кнопки изменится класс, исправлять локатор придётся только один раз.
????
Класс, в который выносят локаторы элементов и действия с ними, называют page
object.
Как задать page object
Шпаргалка: Page Object Model
2
В page object включают локаторы элементов и методы взаимодействия с этими локаторами.
Например, нужно протестировать кнопку «Войти» в приложении Mesto и использовать POM.
Общий алгоритм будет такими:
1. Создать класс страницы авторизации. Пусть он называется
LoginPageMesto
2. Добавить классу приватное поле
driver
. С его помощью программа будет искать элементы по описаниям локаторов. Поле нужно будет инициализировать в конструкторе класса.
3. Описать локаторы нужных элементов как поля класса.
4. Добавить конструктор класса page object. Так ты сможешь создавать экземпляры
LoginPageMesto в разных тестах.
5. Описать действия с элементами страницы как методы класса. Сейчас метод один
— нажатие кнопки «Войти».
// импортировали классы By и WebDriver, которые будут использоваться в коде import org.openqa.selenium.By; import org.openqa.selenium.WebDriver;
// Шаг 1. Создали page object — класс для страницы public class LoginPageMesto {
// Шаг 2. добавили поле driver private WebDriver driver;
// Шаг 3. Добавили локатор кнопки «Войти» private By signInButton = By.className("auth-form__button");
// Шаг 4. Добавили конструктор класса page object public LoginPageMesto(WebDriver driver){ this.driver = driver; // Инициализировали в нём поле driver
}
// Шаг 5. Добавили метод, который кликает по кнопке «Войти» public void clickSignInButton() { driver.findElement(signInButton).click();
}
}
Поле driver обычно задают перед описанием локаторов, а конструктор класса page object
— перед методами. Эти строчки кода будут одинаковыми для всех классов.
Как описать локатор в POM
Чтобы описать элемент как поле класса, нужно:
1. Добавить классу поле. Выбрать ему имя, которое укажет на описанный элемент.
Например, emailField для поля «Email».
Шпаргалка: Page Object Model
3 2. Задать полю класс
By и модификатор видимости private
. Приватность полей гарантирует, что локатор нельзя будет изменить извне класса.
3. Присвоить полю локатор для поиска нужного элемента. Например,
= By.id("email")
Например, page object формы авторизации Mesto будет таким:
import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class LoginPageMesto {
// локатор поля «Email» private By emailField = By.id("email");
// локатор поля «Пароль» private By passwordField = By.id("password");
// локатор кнопки входа в приложение private By signInButton = By.className("auth-form__button");
}
Обрати внимание: описаны не все элементы страницы. В page object нет логотипа и кнопки регистрации. Это потому, что они участвуют в тесте.
????
В POM описывают только элементы, которые участвуют в тесте.
В ещё вpage object необязательно хранить целую страницу. В класс можно выделить несколько отдельных элементов. Например, шапку, футер и боковое меню, если они одинаковые на каждой странице.
Так делают, чтобы собрать схожие локаторы в одном классе. Если хранить их в классах разных страниц, может возникнуть путаница. Она приведёт к ошибкам при изменении локатора.
Почему стоит описывать локаторы как поля класса
Код тестов становится понятнее. Описания локаторов бывают достаточно сложными. Они утяжеляют код теста. Если спрятать локаторы на уровень page object, работать с кодом станет проще.
Можно переиспользовать описания локаторов. Одно из преимуществ паттерна POM — переиспользование локаторов. Локатор как поле класса можно описать один раз. А потом использовать его в разных методах одного page object. Это удобно, если тест несколько раз взаимодействует с одним элементом.
Удобно вносить изменения. Элементы и содержание веб-страниц могут меняться. И тесты приходится адаптировать под эти изменения. Например, разработчики переименовали
Шпаргалка: Page Object Model
4
кнопку «Войти». Теперь она называется «Вбежать». Если имя использовалось для локатора, без POM пришлось бы править все места кода, где задействована кнопка. Итого — десятки правок и море ручной работы. А с POM нужно будет поменять одно поле.
Работа с методами в POM
Все методы в POM делятся на два типа:
совершают действия с элементами,
выполняют проверки.
Например, к действиям относятся клик по кнопке и выбор элемента из списка. Эти методы имитируют поведение пользователя на странице. import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class LoginPageMesto { private WebDriver driver; private By signInButton = By.className("auth-form__button");
// метод кликает по кнопке «Войти» public void clickSignInButton() { driver.findElement(signInButton).click();
}
}
Проверки — это методы, которые проверяют свойства элементов. Например, видимость элемента или соответствие отображаемого на нём текста ожидаемому.
import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class LoginPageMesto { private WebDriver driver;
// локатор кнопки входа в приложение private By signInButton = By.className("auth-form__button");
// метод проверяет, активна ли кнопка «Войти» public boolean checkSignInIsEnabled() { return driver.findElement(signInButton).isEnabled();
}
}
Объединение методов: шаг
Иногда удобнее оперировать сразу несколькими действиями или проверками. Внутри page object можно группировать методы и объединять их в шаги.
Шпаргалка: Page Object Model
5
Шаг — это метод, который хранит последовательность действий или проверок. В шаг объединяют методы, которые вместе приводят к какому-то результату.
Допустим, в коде есть три метода, которые совершают действия с элементами. Это:
заполнение поля email,
заполнение поля пароль,
клик по кнопке «Войти».
Все они необходимы для авторизации. Можно создать шаг «логин пользователя» и объединить в нём эти методы.
Как создать шаг
Чтобы объединить методы в шаг, нужно:
1. Создать новый метод. Дать ему имя, которое отразит результат шага. Например, шаг авторизации можно назвать login
2. Внутри шага вызвать методы с действиями или проверками в нужном порядке.
Посмотри, как объединить методы авторизации:
import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class LoginPageMesto { private WebDriver driver;
// локатор поля ввода «Email» private By emailField = By.id("email");
// локатор поля «Пароль» private By passwordField = By.id("password");
// локатор кнопки входа в приложение private By signInButton = By.className("auth-form__button");
// конструктор класса public LoginPageMesto(WebDriver driver){ this.driver = driver;
}
// метод заполняет поля «Email» public void setUsername(String username) { driver.findElement(emailField).sendKeys(username);
}
// метод заполняет поля «Пароль» public void setPassword(String password) { driver.findElement(passwordField).sendKeys(password);
}
// метод кликает по кнопке авторизации public void clickSignInButton() { driver.findElement(signInButton).click();
}
// метод авторизации в приложении: объединяет ввод email, пароля и клик по кнопке
// это и есть шаг
Шпаргалка: Page Object Model
6
public void login(String username, String password){ setUsername(username); setPassword(password); clickSignInButton();
}
}
Теперь шаг создан: метод login можно вызвать в коде теста. Использование шага скроет детали авторизации и сделает программу лаконичнее.
Теперь можно вернуться к задаче и написать код автотеста. Программа должна проверить страницу авторизации Mesto: ввести почту и пароль, затем кликнуть по кнопке входа в приложение.
С POM тест-код будет таким:
import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import com.example.pagewidgets.LoginPageMestoSelenium; import org.junit.Test; import org.junit.After; public class Praktikum { private WebDriver driver;
@Test public void loginTest() {
ChromeOptions options = new ChromeOptions(); // Драйвер для браузера options.addArguments("--no-sandbox", "--headless", "--disable-dev-shm-usage"); driver = new ChromeDriver(options); driver.get("https://qa-mesto.praktikum-services.ru/");
// создать объект класса страницы авторизации
LoginPageMesto objLoginPage = new LoginPageMesto(driver);
// выполнить авторизацию objLoginPage.login("Введи сюда email твоей учётной записи",
"Введи сюда пароль твоей учётной записи");
}
@After public void tearDown() {
// Закрыть браузер driver.quit();
}
}
В коде автотеста не потребовалось описывать локаторы. Или детализировать, из каких действий состоит авторизация. Достаточно было вызвать метод login из соответствующего page object.
Шпаргалка: Page Object Model
7
Обрати внимание: чтобы взаимодействовать со страницей, создали экземпляр класса. Если выполняешь действия, которые реализуются в методах другого page object, обязательно создай его экземпляр.
// объект класса страницы авторизации
LoginPageMesto objLoginPage = new LoginPageMesto(driver);
О чём стоит помнить
✅
Лучше давать шагам осмысленные имена.
Название должно отражать последовательность действий, которую метод запускает. В идеале можно читать код теста и не заглядывать в page object.
Примеры хороших названий — это register и logout
. Они указывают на результат выполнения шагов — регистрацию и выход из системы.
Неудачные названия: clickButton
, enterValue
, inputName
. Они слишком абстрактные. Имя inputName не подойдёт для шага, если в нём есть дополнительные проверки. Непонятно, какую кнопку нажимает clickButton и куда вводит значение enterValue
. Допустим, когда создавались эти шаги, на странице была одна кнопка и одно поле. Но в будущем это может измениться.
☝
Когда объединяешь методы, соблюдай баланс.
Не стоит объединять все действия в шаги.Это бессмысленно: код будет лаконичным, но непонятным. И создание шагов займёт больше ресурсов, чем освободит.
Например, нужно написать тест, который:
проверяет, что email в заголовке главной страницы соответствует email, с которым пользователь залогинился;
разлогинивается.
В page object описывают два поля с email в заголовке и кнопку «Выйти». Представь, что в методе checkEmailAndSignOut объединили проверку email и нажатие кнопки выхода. Основная часть кода будет очень лаконичной и красивой:
@Test public void checkEmailAndUnloginTest() {
Шпаргалка: Page Object Model
8
// создать объект класса страницы авторизации
HomePageMesto objHomePage = new HomePageMesto(driver);
// выполнить шаг objHomePage.checkEmailAndSignOut();
}
Но так делать не стоит. Проверка email логически никак не связана с выходом из приложения. Они идут друг за другом только в этом тесте. Значит, этот шаг вряд ли будет использоваться в других тестах.
А вот шаг с выходом из приложения требуется часто. Поэтому следует создать два отдельных метода — checkEmail и signOut
@Test public void checkEmailAndUnloginTest() {
// создать объект класса страницы авторизации
HomePageMesto objHomePage = new HomePageMesto(driver);
// выполнить два действия objHomePage.checkEmail(); objHomePage.signOut();
}
Мельчить тоже не нужно.Если прописывать только одинарные действия, код будет громоздким.
Представь, что твоя программа должна удалить из поля field уже введённый текст и добавить туда новое значение. Не стоит создавать метод на каждое из этих действий. Вряд ли тебе понадобится только удалить текст из поля или только добавить его. Лучше создать метод, который объединит эти действия. Его ты сможешь использовать в других тестах:
import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; public class HomePageMesto { private WebDriver driver;
// локатор поля private By someField = ...;
// конструктор класса public HomePageMesto(WebDriver driver){ this.driver = driver;
}
// метод заполняет поля someField public void enterValueInSomeField(String newValue) { driver.findElement(someField).clear(); driver.findElement(someField).sendKeys(newValue);
Шпаргалка: Page Object Model
9
}
} public class Praktikum { private WebDriver driver;
@Test public void enterNewValueInFieldTest() {
// создать объект класса страницы авторизации
HomePageMesto objHomePage = new HomePageMesto(driver);
// выполнить два действия
String newValue = "Новое значение"; objHomePage.enterValueInSomeField(newValue);
}
}
Главное, чтобы шаг был логически единым. Тогда его можно будет переиспользовать в разных тестах.