Добрый день.
Паттерн Page Object, реализуемый с помощью библиотеки PageFactory из состава WebDriver, приобрел заслуженную популярность по следующим причинам:
2. Каждый элемент web-интерфейса описывается один раз. Если что-то меняется в интерфейсе, то изменения нужно отразить в одном месте.
3. Тесты не работают с 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 можно играть в любые игры перед тем как сформировать из нее локатор. Соответственно, каким бы заковыристым не оказался элемент на странице, до него можно будет дотянуться.
Предположу, что изложенные варианты – не единственные, поэтому дополнения и замечания приветствуются.
Всего доброго.
Что такое качество программного обеспечения и как его улучшить: теория и практика, задачи и решения, подводные камни и обходные пути.
Pingback : OpenQuality.ru | Качество программного обеспечения | February 1, 2014
[…] • В блоге опубликована заметка “WebDriver, PageObject и динамические локаторы“. […]