Ожидания — не самый приятный процесс, где бы он ни происходил. Ожидания в автотестах — отдельная боль. Избавиться от них невозможно, но есть способы организовать их работу в более удобной форме, нежели Thread.sleep()
.
Чтобы собрать вместе и систематизировать информацию по этой теме, рассмотрю все варианты написания ожиданий для автоматизированного тестирования UI посредством Java и Selenium, с которыми мне приходилось работать, а именно ожидания, предоставляемые Selenium, возможность написания собственных ожиданий и библиотека Awaitility.
Selenium waiting methods
Implicit Wait
Implicit Wait, или неявное ожидание, — пожалуй, самый популярный способ ожидания в Selenium благодаря своей легкости в использовании.
Чтобы использовать Implicit Wait в автотестестах, достаточно:
- установить его всего 1 раз,
- указать вручную лимит ожидания.
После того, как команда исполнится, Implicit Wait будет действовать на протяжении всего пробега автотестов и ожидать указанное время прежде, чем выбросить NoSuchElementException (или не выбрасывать, если необходимый элемент на странице найден). Не устанавливать Implicit Wait равносильно нулевому лимиту времени, и исключение пробросится сразу.
Чтобы установить Implicit Wait, необходимо написать всего одну строку после установки драйвера, и таким образом мы установим лимит ожидания 10 секунд:
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Implicit Wait можно использовать для:
- ожидания полной загрузки страницы — pageLoadTimeout();
- ожидания появления элемента на странице — implicitlyWait();
- ожидания выполнения асинхронного запроса — setScriptTimeout();
Установка использования неявного ожидания будет выглядеть следующим образом:
Explicit Wait
Explicit wait, или явное ожидание, чаще используется для ожидания определенного условия, которое должно быть выполнено прежде, чем тест пойдет дальше.
О явном ожидании стоит помнить следующие вещи:
- ожидание сработает именно там, где оно указано;
- как и неявному ожиданию, ему необходимо указать лимит времени;
- ожидает выполнения необходимого условия;
- ждет завершения Ajax request.
Использовать явное ожидание можно через WebDriverWait. Инициализация будет происходить следующим образом:
WebDriverWait wait = new WebDriverWait(driver,10);
где driver является референсом к нашему используемому WebDriver, а число 10 — TimeOut в секундах.
В тесте само ожидание уже будет выглядеть примерно так:
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector("some_element"));
Класс ExpectedConditions предоставляет нам ряд вещей, которых мы можем дожидаться во время пробега теста. Они все достаточно легко читаемы, что облегчит жизнь как вам, так и людям, которым, возможно, придется поддерживать ваши автотесты.
Вот полный список всего, что вам предлагает подождать ExpectedConditions:
alertIsPresent()фиксед
elementSelectionStateToBe()
elementToBeClickable()
elementToBeSelected()
frameToBeAvaliableAndSwitchToIt()
invisibilityOfTheElementLocated()
invisibilityOfElementWithText()
presenceOfAllElementsLocatedBy()
presenceOfElementLocated()
textToBePresentInElement()
textToBePresentInElementLocated()
textToBePresentInElementValue()
titleIs()
titleContains()
visibilityOf()
visibilityOfAllElements()
visibilityOfAllElementsLocatedBy()
visibilityOfElementLocated()
В тесте создание и использование неявного ожидания будут выглядеть следующим образом:
Разница между Implicit и Explicit Wait
Implicit Wait |
Explicit Wait |
Указывается один раз, потом работает для всей сессии пробега. |
Срабатывает только там, где указано. |
В основном применяется для findElement(); findElements(); методов. |
Ожидает выполнения условия. |
При проверке на отсутствие элемента будет задерживать тест. |
Отсутствие элемента может быть необходимым условием для завершения ожидания. |
Написание собственных ожиданий
Ожидания Selenium не всегда способны удовлетворить потребности тестировщика. В таких случаях мы можем сами написать методы, которые удержат автотесты от падения. Работать кастомные ожидания будут по тому же принципу, что и Explicit Wait, т.е. срабатывать в той части теста, в которой указаны, а условие, которого необходимо дождаться, нужно написать самим как некий аналог класса ExpectedConditions. Хранить ли свои условия в отдельном классе или в том же, где и написанный способ ожидания, и нужно ли разделять метод ожидания и условие или достаточно будет оставить их прописанными в едином методе, зависит от условий проекта и предпочтений тестировщика.
Чтобы написать ожидание самим, потребуется не так много: старый добрый цикл while() и System.currentTimeMillis();
Выглядеть это может примерно таким образом:
Условие, которое мы ждем в этом примере — element.isDisplayed()
, его можно вынести в отдельный метод, возвращающий boolean, и таким образом сам метод ожидания можно прописать единожды и просто передавать туда разные условия в формате boolean.
Awaitility library
Пожалуй, лучшее, ну или, по крайней мере, мое любимое, решение проблемы ожиданий. Awaitility применима не только в автоматизации тестирования, однако я ограничусь рассмотрением ее использования на примерах тестов. Эта библиотека упростит вам жизнь при написании собственных ожиданий; все, что сказано про аналог кастомных ожиданий с Explicit Wait и ExpectedConditions, будет справедливо и здесь. То же касается и того, как вы предпочтете прописать условия, которых хотите дождаться. В рамках этой статьи рассмотрена только часть возможностей данной библиотеки. Если вам интересно почитать обо всех возможностях, можете ознакомиться с официальной документацией. Здесь я хочу обратить внимание на те моменты, которые мне показались максимально полезными, и просто поделиться тем, что есть такая замечательная штука, которая помогает стабилизировать автотесты.
Awaitility library позволит:
- дождаться выполнения асинхронных запросов,
- установить как максимум, так и минимум ожидаемого времени,
- проигнорировать выпадающие исключения (в таком случае по истечению лимита времени будет выброшен ConditionTimeoutException),
- использовать Assertion в качестве ожидаемого условия,
- использовать polling.
Синтаксис довольно читабельный; Awaitility позволяет понять, что и куда вызывается для определения лимита времени, игнорирования исключений, где устанавливаем polling и чего ожидаем в финале нашего метода. Внутреннее написание ожидания может выглядеть так — остается только вызвать его в тесте. Хранить подобные методы стоит все же отдельно от тестов.
Отдельным примером хочу показать ожидание Assertion, именно этот метод кажется мне особенно удобным, так как убивает сразу двух зайцев и позволяет не прописывать лишних строк кода:
Это та информация, которой я хотела поделиться об ожиданиях.
Более подробно вы можете ознакомиться с Awaitility по ссылке.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: