Настоящие пэдж-объекты
09 Jul 2016Недавно я писал о том, что на самом деле нельзя хардкодить.
Давайте рассмотрим этот принцип на примере пэдж объектов.
Классический пэдж обжект
У тестировщиков-автоматизаторов очень популярен паттерн “Пэдж Обжект”. Собственно, это самый популярный в мире объект поклонения после статуи Будды в Лэшане и Шестого Айфона.
Суть его в том, что все селекторы, по которым ищутся элементы на веб-страничке тестируемого приложения, выносятся… точно, в константы:
public class RegistrationPage {
@FindBy(name = "firstName")
public WebElement firstName;
@FindBy(name = "lastName")
public WebElement lastName;
@FindBy(name = "birthday")
public WebElement birthday;
}
Красиво, да? Такие пэдж объекты хороши тем, что один и тот же локатор не приходится дублировать в сотне разных тестов. Когда локатор меняется, его нужно поменять всего в одном месте.
А тесты не нужно часто менять, потому что они используют пэдж объект:
@Test
public void userCanRegister() {
RegistrationPage page = new RegistrationPage(webdriver);
firstName.sendKeys("Bruce");
lastName.sendKeys("Willis");
birthday.sendKeys("19.03.1955");
}
Такой подход стал особенно популярен с лёгкой руки Мартина Фаулера, который выдумал Золотое Правило Автоматизаторов:
В тесте не должно быть ни одного локатора. Локаторы должны быть спрятаны в пэдж объектах. Если в тесте виден локатор - это негодный тест.
В чём же подвох?
Мы забываем, что меняются не только локаторы. Как я рассказывал в изначальной статье, меняется логика работы с элементами. Допустим, есть у вас сотня тестов, в которых есть такая строчка:
birthday.sendKeys("19.03.1955");
Да, типа хорошо, если меняется локатор - сотня тестов останется нетронутой.
Но что если этот элемент из <input>
вдруг превратиться в контрол типа “календарь”?
Знаете, в котором нужно сначала кликнуть иконку календаря, потом выбрать год, потом месяц, и только потом день.
Упс!
Теперь вам придётся перелопатить всю сотню тестов. Да ещё и разобраться хорошенько, в каких нужно выбирать год, а в каких не нужно. В каких нужно менять месяц, а в каких не нужно. И как эти тесты будут работать в последний день месяца или года.
Упс! Всё пропало, шеф!
Что же делать?
Вот тут и вступает в силу правило: выносить нужно не константы, а логику.
В пэдж объекте должно быть не поле birthday
, а метод
public class RegistrationPage {
public void enterBirthday(String birthday) {
$(By.name("birthday")).sendKeys(birthday);
// а потом - вся логика календаря здесь
}
}
Вот теперь действительно, если поменяется логика работы с элементом “birthday” (в том число локатор!), ни один тест не поменяется - только пэдж объект.
Понятное дело, в этом случае поля пэдж объекта должны быть приватными, чтобы никто не мог использовать их напрямую, а только через методы пэдж объекта.
Ну а в случае Selenide поля так и вовсе становятся ненужными, ведь гораздо легче использовать доллар (как в примере выше).
Вот это труёвый пэдж объект!
Контрольный в мозг
Давайте проверим, что мы понимаем друг друга правильно.
Если вы согласны с приведёнными выше доводами, то вы тоже считаете, что аннотации @FindBy
не нужны, PageFactory
не нужна.
И инифиализировать пэдж-обжект нужно только с помощью конструктора:
MyPage page = new MyPage();
Никаких фабрик, аннотаций и другой чёртовой магии. Она точно добавляет сложности и точно не решает никаких проблем.
А если уж по чесноку, я думаю, что пэдж обжекты вообще не нужны. Но об этом отдельная статья.
Автоматизируйте с умом, други, и не забывайте главное правило из книжки “Design patterns”:
Объект - это не данные и операции с ними (как учат в школе).
Объект - это поведение.