Перейти к основному содержимому

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

· 4 мин. чтения

1. Введение

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

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

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

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

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

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 ForEachHomePage {

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 , это также может быть представлено с помощью By API:

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 ForEachAboutPage {

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

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

public class ForEachAbout {

private SeleniumConfig config;

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

// navigate and getTitle methods
}

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

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

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

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

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

4. Вывод

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

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