«1. Введение

В этой статье мы продолжим предыдущую запись и продолжим улучшать наше тестирование Selenium/WebDriver, представив шаблон Page Object.

2. Добавление Selenium

Давайте добавим в наш проект новую зависимость, чтобы писать более простые и читаемые утверждения:

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-all</artifactId>
    <version>1.3</version>
</dependency>

Последнюю версию можно найти в центральном репозитории Maven.

2.1. Дополнительные методы

В первой части серии мы использовали несколько дополнительных служебных методов, которые мы собираемся использовать и здесь.

Мы начнем с метода navigationTo(String url) – который поможет нам перемещаться по разным страницам приложения:

public void navigateTo(String url) {
    driver.navigate().to(url);
}

Затем clickElement(элемент WebElement) – в качестве имени подразумевает — позаботится о выполнении действия щелчка по указанному элементу:

public void clickElement(WebElement element) {
    element.click();
}

3. Шаблон объекта страницы

Selenium предоставляет нам множество мощных низкоуровневых API-интерфейсов, которые мы можем использовать для взаимодействия с HTML-страница.

Однако по мере роста сложности наших тестов взаимодействие с низкоуровневыми необработанными элементами DOM не является идеальным. Наш код будет сложнее изменить, он может сломаться после небольших изменений пользовательского интерфейса и, проще говоря, будет менее гибким.

Вместо этого мы можем использовать простую инкапсуляцию и перенести все эти низкоуровневые детали в объект страницы.

Прежде чем мы начнем писать наш объект первой страницы, хорошо иметь четкое представление о шаблоне, поскольку он должен позволить нам эмулировать взаимодействие пользователя с нашим приложением.

Объект страницы будет вести себя как своего рода интерфейс, который будет инкапсулировать детали наших страниц или элементов и будет предоставлять высокоуровневый API для взаимодействия с этим элементом или страницей.

Таким образом, важной деталью является предоставление описательных имен для наших методов (например, clickButton(), navigationTo()), так как нам будет проще воспроизвести действие, предпринятое пользователем, и, как правило, это приведет к лучший API, когда мы объединяем шаги вместе.

Хорошо, теперь давайте продолжим и создадим наш объект страницы – в данном случае нашу домашнюю страницу:

public class BaeldungHomePage {

    private SeleniumConfig config;
 
    @FindBy(css = ".nav--logo_mobile")
    private WebElement title;
    @FindBy(css = ".menu-start-here > a")
    private WebElement startHere;

    // ...

    public StartHerePage clickOnStartHere() {
        config.clickElement(startHere);

        StartHerePage startHerePage = new StartHerePage(config);
        PageFactory.initElements(config.getDriver(), startHerePage);

        return startHerePage;
    }
}

Обратите внимание, как наша реализация работает с низкоуровневыми деталями DOM и предоставляет хороший, высокоуровневый API.

Например, аннотация @FindBy позволяет нам предварительно заполнить наши WebElements, это также может быть представлено с помощью API By:

private WebElement title = By.cssSelector(".header--menu > a");

Конечно, оба допустимы, однако использование аннотаций немного чище .

Также обратите внимание на цепочку — наш метод clickOnStartHere() возвращает объект StartHerePage — где мы можем продолжить взаимодействие:

public class StartHerePage {

    // Includes a SeleniumConfig attribute

    @FindBy(css = ".page-title")
    private WebElement title;

    // constructor

    public String getPageTitle() {
        return title.getText();
    }
}

Давайте напишем быстрый тест, в котором мы просто переходим на страницу и проверьте один из элементов:

@Test
public void givenHomePage_whenNavigate_thenShouldBeInStartHere() {
    homePage.navigate();
    StartHerePage startHerePage = homePage.clickOnStartHere();
 
    assertThat(startHerePage.getPageTitle(), is("Start Here"));
}

Важно принять во внимание, что наша домашняя страница отвечает за:

  1. Based on the given browser configuration, navigate to the page.
  2. Once there, validate the content of the page (in this case, the title).

Наш тест очень прост; мы переходим на домашнюю страницу, выполняем щелчок по элементу «Начать здесь», который приведет нас на страницу с тем же именем, и, наконец, мы просто проверяем наличие заголовка.

После запуска наших тестов будет выполнен метод close(), и наш браузер должен закрыться автоматически.

3.1. Разделение проблем

Другая возможность, которую мы можем принять во внимание, может состоять в разделении задач (даже больше), имея два отдельных класса, один из которых позаботится о наличии всех атрибутов (WebElement или By) нашей страницы:

public class BaeldungAboutPage {

    @FindBy(css = ".page-header > h1")
    public static WebElement title;
}

~~ ~ Другой позаботится о том, чтобы реализовать всю функциональность, которую мы хотим протестировать:

public class BaeldungAbout {

    private SeleniumConfig config;

    public BaeldungAbout(SeleniumConfig config) {
        this.config = config;
        PageFactory.initElements(config.getDriver(), BaeldungAboutPage.class);
    }

    // navigate and getTitle methods
}

Если мы используем атрибуты By и не используем функцию аннотации, рекомендуется добавить частный конструктор на нашу страницу. класс, чтобы предотвратить его создание.

Важно отметить, что нам нужно передать класс, содержащий аннотации, в данном случае класс BaeldungAboutPage, в отличие от того, что мы сделали в нашем предыдущем примере, передав ключевое слово this.

@Test
public void givenAboutPage_whenNavigate_thenTitleMatch() {
    about.navigateTo();
 
    assertThat(about.getPageTitle(), is("About Baeldung"));
}

Обратите внимание, что теперь мы можем сохранить все внутренние детали взаимодействия с нашей страницей в реализации, и здесь мы действительно можем использовать этот клиент на высоком, удобочитаемом уровне.

4. Заключение

«В этом кратком руководстве мы сосредоточились на улучшении использования Selenium/WebDriver с помощью шаблона Page-Object. Мы рассмотрели различные примеры и реализации, чтобы увидеть практические способы использования шаблона для взаимодействия с нашим сайтом.

Как всегда, реализацию всех этих примеров и фрагментов можно найти на GitHub. Это проект на основе Maven, поэтому его легко импортировать и запускать.