И Selenium, и WebDriver (который сейчас является преемником Selenium) предоставляют хороший способ функционального тестирования веб-приложений в нескольких целевых средах без ручной работы. В прошлом веб-интерфейсы создавались с использованием навигации по страницам, чтобы пользователи могли отправлять формы и т. Д. В настоящее время все больше и больше веб-приложений используют Ajax и, следовательно, действуют и выглядят как настольные приложения. Однако это создает проблемы для тестирования — Selenium и WebDriver предназначены для работы с пользовательскими взаимодействиями, приводящими к навигации по страницам, и не очень хорошо работают с приложениями AJAX из коробки.
В частности, в приложениях, основанных на GWT, есть эта проблема, но я нашел несколько способов разработать полезные и эффективные тесты. GWT также ставит другие вопросы, касающиеся имитации пользовательского ввода и определения местоположения элементов DOM, и я обсуждаю их ниже. Обратите внимание, что мои примеры кода используют Groovy для краткости, но их довольно легко преобразовать в код Java.
Проблема 1: Обработка асинхронных изменений
Одна из проблем, с которой разработчики сталкиваются довольно быстро при тестировании приложений на основе GWT, — это обнаружение и ожидание реакции на взаимодействие с пользователем. Например, пользователь может нажать кнопку, которая приводит к вызову AJAX, который либо завершится успешно, и закроет окно, либо, альтернативно, покажет сообщение об ошибке. Нам нужен способ блокировки до тех пор, пока мы не увидим ожидаемые изменения, с тайм-аутом, чтобы мы могли потерпеть неудачу, если не увидим ожидаемых изменений.
Решение: используйте WebDriverWait
Самый простой способ сделать это — воспользоваться WebDriverWait (или Selenium’s Wait). Это позволяет вам подождать условие и продолжить, когда оно оценивается как истинное. Ниже я использую код Groovy для краткости использования замыканий, но то же самое можно сделать в Java, хотя с немного большим количеством кода из-за необходимости в анонимных классах.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
def waitForCondition(Closure closure) { int timeout = 20 WebDriverWait w = new WebDriverWait(driver, timeout) w.until({ closure() // wait until this closure evaluates to true } as ExpectedCondition)}def waitForElement(By finder) { waitForCondition { driver.findElements(finder).size() > 0; }}def waitForElementRemoval(By finder) { waitForCondition { driver.findElements(finder).size() == 0; }}// now some sample test code submitButton.click() // submit a form// wait for the expected error summary to show upwaitForElement(By.xpath("//div[@class='error-summary']"))// maybe some more verification here to check the expected errors// ... correct error and resubmitsubmitButton.click()waitForElementRemoval(By.xpath("//div[@class='error-summary']"))waitForElementRemoval(By.id("windowId")) |
Как видно из примера, ваш код может сосредоточиться на реальной логике тестирования, одновременно бесперебойно обрабатывая асинхронную природу приложений GWT.
Проблема 2: Расположение элементов, когда у вас мало контроля над DOM
В веб-приложениях, использующих шаблоны (JSP, Velocity, JSF и т. Д.), У вас есть хороший контроль и легкий обзор структуры DOM, которую будут иметь ваши страницы. С GWT это не всегда так. Часто вы имеете дело с вложенными элементами, которые вы не можете контролировать на хорошем уровне.
С помощью WebDriver и Selenium вы можете нацеливать элементы, используя несколько методов, но наиболее полезными являются идентификатор элемента DOM и XPath. Как мы можем использовать их для получения поддерживаемых тестов, которые не ломаются с небольшими изменениями макета?
Решение: используйте XPath в сочетании с идентификаторами, чтобы ограничить область действия
По моему опыту, для разработки функциональных тестов GWT в WebDriver вы должны использовать несколько свободный XPath в качестве основного средства поиска элементов и дополнить его, ограничивая эти вызовы идентификатором DOM, где это применимо.
В частности, используйте идентификаторы в элементах верхнего уровня, таких как окна или вкладки, которые уникальны в вашем приложении и не будут существовать более одного раза на странице. Они могут помочь расширить ваши выражения XPath, которые могут искать заголовки окон или форм, метки полей и т. Д.
Вот несколько примеров, чтобы вы начали. Обратите внимание, что мы используем // и * в нашем XPath для обеспечения гибкости наших выражений, чтобы изменения макета не нарушали наши тесты, если они не являются основными.
|
01
02
03
04
05
06
07
08
09
10
11
|
By byUserName = By.xpath("//*[@id='userTab']//*[text()='User Name']/..//input")WebElement userNameField = webDriver.findElement(byUserName)userNameField.sendKeys("my new user")// maybe a user click and then wait for the window to disappearBy submitLocator = By.xpath("//*[@id='userTab']//input[@type='submit']")WebElement submit = webDriver.findElement(submitLocator)submit.click()// use our helper method from Problem 1waitForElementRemoval By.id("userTab") |
Проблема 3: Нормальные методы взаимодействия элементов не работают!
GWT и его производные (Vaadin, GXT и т. Д.) Часто делают некое волшебство за кулисами при управлении состоянием DOM. Для разработчика это означает, что вы не всегда имеете дело с простыми элементами <input> или <select> и т. Д. Простая установка значения поля обычными средствами может не сработать, а использование методов кликов WebDriver или Selenium может не сработать.
WebDriver улучшился в этом отношении, но проблемы все еще сохраняются.
Решение: к сожалению, только некоторые обходные пути
Основные проблемы, с которыми вы, вероятно, столкнетесь, касаются ввода в поля и нажатия элементов.
Вот несколько вариантов, которые я нашел необходимыми в прошлом, чтобы обойти клики, которые не работают, как ожидалось. Попробуйте их, если вы столкнулись с проблемами. Примеры приведены в Selenium, но их можно адаптировать к соответствующим вызовам в WebDriver, если они вам требуются. Вы также можете использовать адаптер Selenium для WebDriver (WebDriverBackedSelenium), если хотите использовать примеры напрямую.
НАЖМИТЕ НА ВОПРОСЫ
Иногда элементы не отвечают на вызов click () в Selenium или WebDriver. В этих случаях вам обычно приходится моделировать события в браузере. Это было правдой больше, чем Selenium до 2.0, чем WebDriver.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
// Selenium's click sometimes has to be simulated with events.def fullMouseClick(String locator) { selenium.mouseOver locator selenium.mouseDown locator selenium.mouseUp locator}// In some cases you need only mouseDown, as mouseUp may be// handled the same as mouseDown.// For example, this could result in a table row being selected, then deselected.def mouseOverAndDown(String locator) { selenium.mouseOver locator selenium.mouseDown locator} |
ВОПРОСЫ ТИПА
Это окольные методы набора текста, которые я смог успешно использовать в прошлом, когда GWT не распознает типизированный ввод.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// fires only key events (works for most GWT inputs)// Useful if WebDriver sendKeys() or Selenium type() aren't cooperating.def typeWithEvents(String locator, String text) { def keyEvents = ["keydown", "keypress", "keyup"] typeWithEvents(locator, text, keyEvents)}// fires key events, plus blur and focus for really picky casesdef typeWithFullEvents(String locator, String text) { def fullEvents = ["keydown", "keypress", "keyup", "blur", "focus"] typeWithEvents(locator, text, fullEvents)}// use this directly to customize which events are fireddef typeWithEvents(String locator, String text, def events) { text.eachWithIndex { ch, i -> selenium.type locator, text.substring(0, i+1) events.each{ event -> selenium.fireEvent locator, event } }} |
Обратите внимание, что точный метод, который работает, должен быть определен методом проб и ошибок, и в некоторых случаях вы можете вести себя по-разному в разных браузерах, поэтому, если вы запускаете свои функциональные тесты в разных средах, вы должны убедиться, что Ваш метод работает для всех них.
Вывод
Надеюсь, некоторые из вас найдут эти советы полезными. Существуют аналогичные советы, но я хотел собрать хороший набор примеров и обходных путей, чтобы другие в похожих ситуациях не заходили в тупики и не тратили время на проблемы, которые требуют много догадок и времени.
Ссылка: Тестирование GWT-приложений с помощью Selenium или WebDriver от наших партнеров JCG в блоге Carfey Software .
- Услуги, практики и инструменты, которые должны существовать в любом доме разработки программного обеспечения, часть 2
- Почему автоматизированные тесты ускоряют вашу разработку
- Не делаете Code Reviews? Какое твое оправдание?
- Уроки в надежности программного обеспечения
- Это приходит ДО вашей бизнес-логики!
- Покрытие кода модульными и интеграционными тестами