Ответ
Плюсы Page Object Model:
- Повышение поддерживаемости: Все локаторы элементов и низкоуровневые взаимодействия с UI инкапсулированы в одном классе. При изменении верстки (например,
idкнопки) правки нужно вносить только в соответствующий Page Object, а не в десятки тестов. - Устранение дублирования кода (DRY): Общие действия (например,
login(),search()) выносятся в методы Page Object и переиспользуются во множестве тестов. - Улучшение читаемости тестов: Тестовые сценарии становятся высокоуровневыми и понятными, они описывают что делать (
loginPage.login("user", "pass")), а не как это делать (driver.findElement(...).sendKeys(...)). - Разделение ответственности: Тесты содержат бизнес-логику и проверки, а Page Objects — детали взаимодействия с конкретной страницей.
- Повторное использование: Page Objects могут быть использованы в разных тестовых наборах (unit, интеграционные, end-to-end).
Минусы Page Object Model:
- Усложнение структуры проекта: Требуется создавать и поддерживать дополнительный слой абстракции (множество классов), что может быть избыточно для очень маленьких или одноразовых проектов.
- Вероятность создания "жирных" Page Objects: Класс может разрастись, содержа сотни методов и локаторов для одной страницы, что затрудняет навигацию по нему.
- Дополнительные усилия на проектирование: Необходимо продумать структуру Page Objects, их взаимосвязи (например, какой метод возвращает новый Page Object) с самого начала.
- Потенциальная хрупкость: Если Page Object плохо спроектирован (например, возвращает
voidвместо следующего состояния), тесты могут стать менее гибкими.
Пример реализации Page Object для страницы логина (Java/Selenium 4):
public class LoginPage {
private final WebDriver driver;
// Локаторы (лучше выносить в отдельные константы или properties)
private final By usernameField = By.id("username");
private final By passwordField = By.id("password");
private final By loginButton = By.cssSelector("button[type='submit']");
private final By errorMessage = By.className("alert-error");
public LoginPage(WebDriver driver) {
this.driver = driver;
// Можно добавить проверку, что мы на нужной странице
new WebDriverWait(driver, Duration.ofSeconds(5))
.until(d -> d.findElement(usernameField).isDisplayed());
}
// Метод для заполнения полей и нажатия кнопки
public HomePage loginWithValidCredentials(String username, String password) {
driver.findElement(usernameField).sendKeys(username);
driver.findElement(passwordField).sendKeys(password);
driver.findElement(loginButton).click();
// Возвращаем Page Object следующей страницы
return new HomePage(driver);
}
// Метод для негативного сценария
public LoginPage loginWithInvalidCredentials(String username, String password) {
driver.findElement(usernameField).sendKeys(username);
driver.findElement(passwordField).sendKeys(password);
driver.findElement(loginButton).click();
// Остаемся на этой же странице, возвращаем this
return this;
}
// Метод для проверки состояния страницы
public String getErrorMessage() {
return driver.findElement(errorMessage).getText();
}
}
// Использование в тесте (JUnit 5)
@Test
public void successfulLogin_NavigatesToHomePage() {
LoginPage loginPage = new LoginPage(driver);
HomePage homePage = loginPage.loginWithValidCredentials("standard_user", "secret_sauce");
// Проверка на новой странице
assertTrue(homePage.isUserMenuDisplayed());
}