В мире тестирования очень популярен шаблон Page Objects. Суть его в том, что для каждой страницы тестируемого приложения создаётся отдельный объект, методы которого инкапсулируют логику работы с отдельными элементами. Считается, что Page Object позволяет избежать дублирования локаторов в тестах.
А Selenide позволяет писать более короткие и читаемые Page Objects.
Вот как выглядит Page Object с Selenide.
public class GoogleSearchPage {
public GoogleResultsPage search(String query) {
$(By.name("q")).setValue(query).pressEnter();
return page(GoogleResultsPage.class);
}
}
public class GoogleResultsPage {
public ElementsCollection results() {
return $$("#ires li.g");
}
}
Как видите, никаких PageFactory
, никаких initElements
и прочего мусора. Ваш Page Object содержит
только вашу логику.
А как же выглядит тест с использованием этих Page Objects? А вот так:
GoogleSearchPage searchPage = open("/login", GoogleSearchPage.class);
GoogleResultsPage resultsPage = searchPage.search("selenide");
resultsPage.results().shouldHave(size(10));
resultsPage.results().get(0).shouldHave(text("Selenide: Concise UI Tests in Java"));
Кто скажет, что это не просто?
Многим полюбился шаблон написания тестов, согласно которому на каждый веб-элемент создаётся поле в page object. У этого подхода есть недостатки, но Selenide позволяет делать и так:
public class GoogleSearchPage {
@FindBy(how = How.NAME, using = "q")
private SelenideElement searchBox;
public GoogleResultsPage search(String query) {
searchBox.setValue(query).pressEnter();
return page(GoogleResultsPage.class);
}
}
public class GoogleResultsPage {
@FindBy(how = How.CSS, using = "#ires li.g")
public ElementsCollection results;
}
Один из недостатков “классического” варианта - это недостаточно динамичный.
Представьте, что вы пишете автотест для страницы, на которой есть английский алфавит из 26 букв.
Вы действительно хотите определить 26 полей в классе AlphabetPage
с аннотациями @FindBy
?
class AlphabetPage {
@Find(By.xpath("//*[@letter='A']"))
WebElement a;
@Find(By.xpath("//*[@letter='B']"))
WebElement b;
// 24 more elements ...
}
И что если пользователь может менять язык, а в разных языках разное количество букв?
Или погодите, не собираетесь ли вы создать 7164 разных пэдж обжектов (под одному на каждый язык)? :)
Ах да, есть же кодогенерация, Lombok, процессинг аннотаций. Давайте, пусть ваше CV разбухнет.
Ещё AI попросите написать эти тысячи пэдж обжектов…
Или вы всё-таки предпочитаете написать один короткий метод?
public void pickLetter(char letter) {
$(by("letter", letter)).click();
}
Хочу напомнить, что изначальный смысл Page Objects состоял в том, чтобы инкапсулировать (то есть прятать!) логику работы с элементами. Тесты не должны ничего знать о веб-элементах, не должны оперировать напрямую с XPath или другими селекторами. Тесты должны использовать публичные методы пэдж объекта.
То есть если уж вы объявляете поля для элементов, то пусть они будут приватными, а все операции с ними пусть осуществляются через публичные методы.
Иначе зачем весь этот ООП?