Тестирование с помощью Selenium/WebDriver и шаблона объекта Page

Тестирование с помощью Selenium / WebDriver и шаблона объекта Page

1. Вступление

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

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

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


    org.hamcrest
    hamcrest-all
    1.3

Последнюю версию можно найти в папкеMaven Central Repository.

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

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

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

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

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

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

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

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

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

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

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

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

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

Хорошо, теперь давайте продолжим иcreate our page object - в данном случае наша домашняя страница:

public class exampleHomePage {

    private SeleniumConfig config;

    @FindBy(css=".header--menu > a")
    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, это также можно представить с помощью APIBy:

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. В зависимости от заданной конфигурации браузера перейдите на страницу.

  2. Оказавшись там, проверьте содержание страницы (в данном случае заголовок).

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

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

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

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

public class exampleAboutPage {

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

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

public class exampleAbout {

    private SeleniumConfig config;

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

    // navigate and getTitle methods
}

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

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

@Test
public void givenAboutPage_whenNavigate_thenTitleMatch() {
    about.navigateTo();

    assertThat(about.getPageTitle(), is("About example"));
}

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

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

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

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