OpenQuality.ru

Качество программного обеспечения

Качество программного обеспечения: в главных ролях

Лента  Радар  Блог  Опыт  
Разум  Видео  Заметки  Эпизоды


WebDriver, Page Object и динамические локаторы

Добрый день.

 

Паттерн Page Object, реализуемый с помощью библиотеки PageFactory из состава WebDriver, приобрел заслуженную популярность по следующим причинам:

 

1. Возможность разделить четыре компонента: вызов драйвера, локаторы (css, xpath, id, name и т.п.), команды драйвера (sendKeys, click и т.п.) и данные (имя пользователя, идентификатор товара и т.п).

2. Каждый элемент web-интерфейса описывается один раз. Если что-то меняется в интерфейсе, то изменения нужно отразить в одном месте.

3. Тесты не работают с web-страницей напрямую, а обращаются к классам, ответственным за тот или иной смысловой блок (страницу, группу страниц, часть страницы).

 

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

 

1. Методы в классах страниц не перегружены локаторами и конструкциями вида driver.findElement(Locator). Присутствуют только операции с web-элементами без излишней деталировки.

2. Методы одного класса могут возвращать объекты другого класса, что упрощает навигацию от одного смыслового блока к другому.

3. Тесты становятся простыми и более читабельными. Они не завязаны ни на команды WebDriver, ни на локаторы. Присутствует только логика теста и входные данные. Соответственно, тесты не нужно менять при изменениях в web-интерфейсе.

4. Еще одним положительным побочным эффектом становится удобство разделения работы над тестами – при минимальной спецификации классы описания страниц и тесты можно реализовывать независимо друг от друга.

 

Наряду с достоинствами, у реализации паттерна Page Object через библиотеку PageFactory есть недостатки. Об одном из них и пойдет речь. Заключается он в том, что реализация PageFactory опирается на аннотации @FindBy, и значения локаторов в этих аннотациях должны быть константами. Но локаторы не всегда бывают статическими. К примеру, мы выводим список пользователей в виде таблицы и хотим кликнуть на одну из ячеек, чтобы выделить ее и затем нажать кнопку Delete. Количество пользователей (и, соответственно, количество ячеек) мы заранее не знаем, поэтому спозиционироваться на той или иной ячейке мы можем лишь с помощью какого-то идентификатора пользователя. К примеру, через такой XPath: “//td[contains(text(),’$UserName’)]”. Но мы не можем записать аннотацию так:

 

@FindBy (xpath="//td[contains(text(),'$UserName')]")
private WebElement locUserName

 

Почему не можем? Потому что заранее не знаем имя пользователя и не можем прописать его в аннотации явным образом, сделав значение аннотации константой. Как быть? По сути, все варианты сводятся к одному: к моменту поиска элемента на web-странице иметь на руках полноценный локатор. Один из возможных вариантов – прописать в аннотации статический элемент более высокого уровня (скажем, тэг таблицы), а потом искать в нем динамический элемент (ячейку):

 

@FindBy (xpath="//table[@id='UserListing']")
private WebElement locUserList;
...
 
WebElement locRequiredUserName = findTableCell(locUserList, userName);
locRequiredUserName.click();
...
 
public WebElement findTableCell (WebElement staticTable, String substitutionValue ) {
 
	String xpath = "//td[contains(text(),'%s')]";
 
	return staticTable.findElement(By.xpath(String.format(xpath, substitutionValue)));	
 
}

 

Эту же идею можно реализовать и без аннотации @FindBy. В этом случае не потребуется описывать элемент более высокого уровня, и нет жесткой привязки к тэгам таблицы и ячейки:

 

private static final String locUserNameXpath = "//td[contains(text(),'%s')]";
...
 
WebElement locRequiredUserName = findWebElementByXpath
					(driver, String.format(locUserNameXpath, userName));
...
 
public WebElement findWebElementByXpath (WebDriver driver, String xpath ) {
 
	return driver.findElement(By.xpath(xpath));	
 
}

 

И напоследок радикальный вариант: взять от PageFactory/PageObject содержание, а не форму: разделять логику теста и реализацию страниц, но делать это собственными силами, без PageFactory и аннотаций. Например, через By-объекты:

 

By locRequiredUserName = By.xpath(userName);
WebElement requiredUsername = driver.findElement(locRequiredUserName);

 

С переменной userName можно играть в любые игры перед тем как сформировать из нее локатор. Соответственно, каким бы заковыристым не оказался элемент на странице, до него можно будет дотянуться.

Предположу, что изложенные варианты – не единственные, поэтому дополнения и замечания приветствуются.

Всего доброго.

Отправить в Twitter, Facebook, ВКонтакте | Опубликовано 28.01.2014 в рубрике "Автоматизация"

Комментарии (1)

  1. Pingback : OpenQuality.ru | Качество программного обеспечения | February 1, 2014

    […] • В блоге опубликована заметка “WebDriver, PageObject и динамические локаторы“. […]



Добавить комментарий

Пожалуйста, исправьте результат: дважды два равно



КРАТКОЕ СОДЕРЖАНИЕ

Что такое качество программного обеспечения и как его улучшить: теория и практика, задачи и решения, подводные камни и обходные пути.


ПУТЕВОДИТЕЛЬ

Проект был основан в 2008 году. За это время часть статей устарела, а некоторые из них вызывают улыбку, но пусть они останутся в том виде, в котором были написаны. Cписок всех статей с краткой аннотацией и разбивкой по рубрикам: открыть.

ПОДПИСКА

Доступ к самым интересным материалам по электропочте и RSS. Подробности.

ИЩЕЙКА