Selenium - Можно ли смешивать неявное ожидание и явное ожидание, как это? - PullRequest
3 голосов
/ 19 марта 2020

Вот курс Удеми (от "Lets Kode It") по разработке инфраструктуры веб-автоматизации с селеном и Java. Но это не вопрос java. Вам необходимо знать селен только на любом из этих языков - javascript, python, ruby, c# & java.

Инструктор разработал класс CustomDriver, который имеет метод / функцию, приведенную ниже. Этот метод ожидает нажатия на элемент, без необходимости писать операторы WebDriverWait повсюду в нашем коде. Сначала он устанавливает неявное ожидание на ноль, выполняет явное ожидание, а затем устанавливает неявное ожидание на исходное значение, которое использовалось в рамках.

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

UPDATE (24 марта 2020 г.) - я уже знаю, что смешивание неявных и явных ожиданий считается плохой практикой, поскольку это может привести к непредсказуемое время ожидания. Я не спрашиваю о непредсказуемых временах ожидания, потому что уже есть множество вопросов и статей на эту тему.

Вместо этого я спрашиваю, что если неявное ожидание каждый раз устанавливается в ноль перед выполнением явного ожидания, тогда это нормально? Это все еще вызовет проблемы непредсказуемых ожиданий? Это вызовет другие проблемы?

/*
 Click element when element is clickable
 @param locator - locator strategy, id=>example, name=>example, css=>#example,
                       tag=>example, xpath=>//example, link=>example
 @param timeout - Duration to try before timeout
 */
public void clickWhenReady(By locator, int timeout) {
    try {
        driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
        WebElement element = null;
        System.out.println("Waiting for max:: " + timeout + " seconds for element to be clickable");

        WebDriverWait wait = new WebDriverWait(driver, 15);
        element = wait.until(
                ExpectedConditions.elementToBeClickable(locator));
        element.click();
        System.out.println("Element clicked on the web page");
        driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
    } catch (Exception e) {
        System.out.println("Element not appeared on the web page");
        driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
    }
}

Ответы [ 3 ]

2 голосов
/ 24 марта 2020

Проблема использования неявного ожидания и явного ожидания сводится к fl aws в том, как ExpectedConditions реализовано в исходном коде Selenium.

Позвольте мне объяснить проблему, проанализировав следующий код:

WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
WebElement element =  new WebDriverWait(driver, 5, 1000).until(ExpectedConditions.elementToBeClickable(By.id("some_id")));
  1. Мы инициализируем драйвер и устанавливаем неявное ожидание на 10 секунд. Это означает, что driver.findElement() будет ждать 10 секунд, пока элемент не будет найден, прежде чем выбросить NoSuchElementException. Это очень важный момент для заметки .
  2. Затем мы устанавливаем явное ожидание с продолжительностью 5 секунд и временем ожидания между опросом 1000 миллисекунд (1 секунда). Это означает, что WebDriverWait будет опрашивать ExpectedConditions, чтобы быть правдой каждую 1 секунду до 5 секунд. Если ExpectedConditions вернет true, опрос остановится и объект, указанный в ExpectedConditions, будет возвращен. В приведенном выше примере кода возвращаемым объектом является WebElement. В случае, если ExpectedConditions ложно через 5 секунд, выдается TimeoutException ( ИЛИ ТАК МЫ ЖДЕМ ). Теперь пришло время посмотреть, что происходит в ExpectedConditions.
  3. Код ExpectedConditions.elementToBeClickable() имеет следующий синтаксис.

    public static ExpectedCondition<WebElement> elementToBeClickable(final By locator) {
        return new ExpectedCondition<WebElement>() {
            @Override
            public WebElement apply(WebDriver driver) {
                WebElement element = visibilityOfElementLocated(locator).apply(driver);
                try {
                    if (element != null && element.isEnabled()) {
                        return element;
                    }
                    return null;
                } catch (StaleElementReferenceException e) {
                    return null;
                }
            }
        };
    }
    
  4. В свою очередь elementToBeClickable выше, в свою очередь, вызывает visibilityOfElementLocated() метод для подтверждения, если элемент виден.

    public static ExpectedCondition<WebElement> visibilityOfElementLocated(final By locator) {
        return new ExpectedCondition<WebElement>() {
            @Override
            public WebElement apply(WebDriver driver) {
                try {
                    return elementIfVisible(driver.findElement(locator));
                } catch (StaleElementReferenceException e) {
                    return null;
                }
            }
        };
    }
    

    5.Примечание как driver.findElement(locator) Вызывается выше в методе visibilityOfElementLocated(). В случае, если элемент не найден, будет применено неявное ожидание в 10 секунд. Поэтому водитель будет ждать 10 секунд, пока не выдаст NoSuchElementException.

Но подождите (каламбур не преднамеренный)! не установлено ли для нашего явного ожидания время ожидания в 5 секунд при условии elementToBeClickable()? Да, это так, но неявное ожидание будет применено первым. WebDriverWait перехватит NoSuchElementException и выдаст TimeoutException через 10 секунд вместо установленного явного ожидания в 5 секунд. В этом и заключается проблема, которую пытается решить решение вопроса. Решение пытается установить неявное ожидание на 0 секунд, чтобы условие явного ожидания выполнялось правильно, а затем сбрасывает неявное ожидание.

Реализация, представленная в Вопросе, выполняет работу без одной детали. Неявное ожидание жестко запрограммировано на 3 секунды, что не идеально. То, как вы предоставляете неявное ожидание как глобальную универсальную константу, очень специфично c. Мы устанавливаем неявное ожидание на драйвере, и мы можем ожидать неявное ожидание, как «драйвер» driver.manage().timeouts().getImplicitWait(). Хотя это и идеально, к сожалению, это НЕ возможно напрямую. Есть обходные пути, у @forresthopkinsa есть довольно интересное решение по созданию расширенных драйверов для получения неявных ожиданий

ОБНОВЛЕНИЕ (24 марта 2020 г.)

В: Этот подход мне подходит, но я не уверен в этом. Может ли смешивание неявных и явных ожиданий, подобных этому, вызывать какие-либо проблемы?

Я спрашиваю, что если неявное ожидание каждый раз устанавливается в ноль перед выполнением явного ожидания, тогда это нормально? Это все еще вызовет проблемы непредсказуемых ожиданий? Это вызовет другие проблемы?

Насколько я понимаю, не должно быть никаких проблем с установкой неявного ожидания на 0, а затем с выполнением явного ожидания и последующим переключением обратно, поскольку нет никаких ограничений на установку неявного ожидание в любой момент времени во время выполнения теста.

Кроме того, если вы думаете об этом, вы действительно не смешиваете неявное ожидание и явное ожидание в решении с точки зрения выполнения кода. На самом деле вы делаете противоположное! Если вы установили неявное ожидание для определенного ненулевого значения, а затем выполнили явное ожидание, то здесь происходит реальное микширование. Сначала выполняется неявное, если применимо, а затем выполняется явное ожидание, приводящее к несоответствиям. Если вы установите неявное ожидание равным 0, вы уберете неявное ожидание из уравнения времени ожидания!

Проблема непредсказуемых ожиданий не возникнет с решением в OP.

2 голосов
/ 23 марта 2020

Я бы не советовал смешивать их. Поскольку Implicit wait в большинстве случаев реализуется на стороне remote системы WebDriver, то есть они обрабатываются в драйвере на основе браузера (например, chromedriver.exe, IEDriverServer.exe), где Explicit Wait - на привязки к локальному языку, такие как Java, ruby, python et c.

Ниже приведен типичный пример того, что происходит, когда вы запускаете скрипт с remote server.

Локальный код -> Удаленный сервер -> Связи локальных языков на удаленном сервере -> удаленный компонент, такой как chromedriver.exe или IEDriverServer.exe. Все становится более сложным, когда у вас есть сетка, так как это может быть еще один слой между цепочкой.

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

При современных технологиях элементы могут визуализироваться в последнее время после его появления. Итак, идти с implicit wait недостаточно, поэтому настоятельно рекомендуем использовать explicit wait. Могут быть некоторые крайние случаи, когда нам, возможно, придется использовать implicit wait, но никогда не смешивайте их оба, если вы планируете в будущем расширить свой сценарий для работы на сетке / с использованием удаленного сервера.

1 голос
/ 31 марта 2020

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

Если вы сбрасываете неявное значение ожидания до 0 для объекта драйвера, используемого явным ожиданием, прежде чем вы вызовете явное ожидание (т.е. вы фактически начинаете ждать), технически это должно работать нормально, потому что вы не смешиваете неявное и явное ожидания. Это жизнеспособная стратегия, если вы можете осуществить ее.

Теперь, как говорится, может потребоваться много работы, чтобы отрегулировать неявное значение ожидания и убедиться, что вы точно отслеживаете его. Еще хуже в общей базе кода, когда другой человек, который приходит, не знает, что это ваша стратегия (или не понимает ее). Вот почему общий совет - не используйте неявные ожидания, вместо этого используйте явные.

Во-вторых, посмотрите, что вы на самом деле делаете; если вы явно меняете значение неявного ожидания перед каждым взаимодействием, когда вы хотите ожидать появления указанного элемента c, вы действительно не так уж далеки от использования явного ожидания. Я бы предположил, что при использовании явного ожидания это сделает ваш код более понятным для тех, кто читает его в будущем, и в результате его будет легче поддерживать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...