何时在Selenium Webdriver中使用显式等待vs隐式等待?

时间:2012-05-01 20:50:34

标签: java selenium-webdriver

我正在使用:

driver.manage().timeouts().implicitlyWait(180, TimeUnit.SECONDS);

但是对于下面的元素

仍然会一直失败
    driver.findElement(By.id("name")).clear();
    driver.findElement(By.id("name")).sendKeys("Create_title_01");

我添加了等待代码:

for (int second = 0;; second++) {
        if (second >= 120) fail("timeout");
        try { if (isElementPresent(By.id("name"))) break; } catch (Exception e) {}
        Thread.sleep(1000);
    }

不应该隐式等待,直到找到一个元素? 如果我使用显式等待而不是我添加的具有Thread.sleep()的代码会更好吗?

8 个答案:

答案 0 :(得分:85)

TL; DR:始终使用显式等待。忘记存在隐式等待。


以下是显式和隐式等待之间差异的快速概述:

显式等待:

  • 记录和定义的行为。
  • 在selenium的本地部分运行(使用代码的语言)。
  • 适用于您能想到的任何条件。
  • 返回成功或超时错误。
  • 可以将元素的缺失定义为成功条件。
  • 可以自定义重试和要忽略的异常之间的延迟。

隐含等待:

  • 未记录且几乎未定义的行为。
  • 在selenium的远程部分(控制浏览器的部分)中运行。
  • 仅适用于查找元素方法。
  • 返回找到的元素或(找不到超时后)。
  • 如果检查元素缺失必须一直等到超时。
  • 除了全局超时之外,
  • 无法自定义。

让我们看一下selenium实际源代码中显式等待和隐式等待的区别。我复制了selenium的python绑定代码,因为python“易于阅读”。

WebDriverWait.until()的代码(明确等待):

def until(self, method, message=''):
    end_time = time.time() + self._timeout
    while(True):
        try:
            value = method(self._driver)
            if value:
                return value
        except self._ignored_exceptions:
            pass
        time.sleep(self._poll)
        if(time.time() > end_time):
            break
    raise TimeoutException(message)

现在使用人类语言:显式等待需要一个方法,如果成功则返回一个值。然后它重复执行给定的方法,其间有延迟。抑制了给定方法的预期误差。如果给定方法返回truish值,则显式wait将返回该值。如果时间用完,则会引发超时异常。

WebDriver.implicitly_wait()的代码比较(为简洁起见删除了评论):

def implicitly_wait(self, time_to_wait):
    self.execute(Command.IMPLICIT_WAIT, {'ms': float(time_to_wait) * 1000})

self.execute()WebDriver.execute(),它会调用RemoteConnection.execute(),据我所知,这反过来会向硒的远端提供RPC。

在人类语言中:隐式等待将消息发送到selenium webdriver的“远程端”。 selenium webdriver的远程端是selenium的一部分,它实际上控制着浏览器。远程端对消息做了什么? “这取决于”。这取决于操作系统和浏览器以及selenium的版本。据我所知,无法保证特定实现的实际行为。

可能的实施是:

  • 反复尝试查找元素直到超时。找到元素后立即返回。
  • 尝试寻找元素。等到超时。再试一次。
  • 等到超时。试着寻找元素。

请注意,隐式等待仅对find element(s)方法生效。

我没有查找selenium远程端的实际源代码。通过阅读the bug reports about implicit and explicit wait in selenium中的评论来收集信息:

我的结论:隐性等待很糟糕。能力有限。该行为未记录且依赖于实现。

显式等待可以做一切隐含的等待可以和更多。由于多个远程过程调用,显式等待的唯一缺点是更多开销。显式等待也有点冗长。但这种冗长使代码显而易见。隐式的显性更好。正确?


进一步阅读:

答案 1 :(得分:4)

你试过流利的等待吗? Wait接口的实现,可以动态配置其超时和轮询间隔。 每个FluentWait实例定义等待条件的最大时间量,以及检查条件的频率。此外,用户可以将等待配置为在等待时忽略特定类型的异常,例如在搜索页面上的元素时使用NoSuchElementExceptions。

请参阅此链接fluent wait description

特别是我以这种方式使用流利的等待:

public WebElement fluentWait(final By locator){
        Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
                .withTimeout(30, TimeUnit.SECONDS)
                .pollingEvery(5, TimeUnit.SECONDS)
                .ignoring(NoSuchElementException.class);

        WebElement foo = wait.until(
new Function<WebDriver, WebElement>() {
            public WebElement apply(WebDriver driver) {
                        return driver.findElement(locator);
                }
                }
);
                           return  foo;              }     ;

正如您已经注意到流畅的等待返回找到了web元素。因此,您只需使用By类型传递定位器,然后就可以对找到的Web元素执行任何操作。

fluentWait(By.id("name")).clear();

希望这可以帮助你)

答案 2 :(得分:4)

隐式等待 - 适用于所有元素的全局设置,如果元素在指定时间之前出现,则脚本将开始执行,否则脚本将抛出NoSuchElementException。在setup方法中使用的最佳方法。仅影响By.findelement()

Thread.sleep() - 它会让脚本停留时间,不好的方式在脚本中使用,因为它无条件地睡眠。如果5%的情况下2秒不够怎么办?

显式等待:等待指定包含/属性更改。当应用程序向系统提供 AJAX 调用并获取动态数据并在UI上呈现时,会使用更多内容。在这种情况下,WebDriverWait是合适的。

答案 3 :(得分:2)

您是否尝试过使用' WebDriverWait '? 我想你想要的是这个:

WebDriverWait _wait = new WebDriverWait(driver, new TimeSpan(0, 0, 2)); //waits 2 secs max
_wait.Until(d => d.FindElement(By.Id("name")));
//do your business on the element here :)

根据我的理解,这几乎可以做你当前的代码。它将不断尝试该方法(忽略未找到的异常),直到达到传递的时间跨度的超时,并且可以输入第三个参数来指定以毫秒为单位的睡眠。 对不起,如果这是隐含的,也是这样做的!

编辑:我今天做了一些阅读并更好地理解了你的问题,并意识到这正是你的隐式等待设置应该做的。将它保留在这里,以防代码本身可以帮助其他人。

答案 4 :(得分:2)

ImplicitWait:

    1. Static Wait 
    2. UnConditional Wait (No conditions are given)
    3. Applicable throughout the program
  

在java中声明隐式等待 - selenium:

driver.manage().timeout().implicitWait(20, TimeUnit.Seconds());

何时使用隐式等待?

建议不要在自动化套件中的任何位置使用隐式等待,因为这是静态的,我们不知道网页元素何时会弹出网站。

即。假设您已设置5秒的隐式等待,并且驱动程序能够在2秒内识别Web元素,因为我们已应用隐式等待驱动程序将等待3秒(直到5秒)。这将减缓自动化进程。

明确等待

  1. 动态等待
  2. 有条件等待。
  3. 整个计划不适用
  4.   

    在Java Selenium中声明显式等待。

    WebDriverWait wait=new WebDriverWait(driver, 20); wait.until(somecondition);
    

    何时使用明确的等待?

    我们应该总是使用显式等待,因为它本质上是动态的。

    即。让我们假设你已经设置了5秒的显式等待,并且驱动程序能够在2秒内识别出web元素,因为我们已经应用了明确的等待驱动程序将不再等待3秒(直到5秒)。司机将在2秒后继续。这将加强自动化过程。

答案 5 :(得分:0)

隐式等待用于在整个测试脚本或程序的每个连续测试步骤之间提供等待时间(例如30秒)。下一步仅在执行上一步

后30秒(或任何时间已过)时执行

语法:

WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);

显式等待用于暂停执行,直到满足特定条件或已定义的最大时间为止。在整个测试脚本或程序的每个连续测试步骤之间应用了隐式等待,而显式等待仅适用于特定实例。

语法:

WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver,30);

答案 6 :(得分:0)

在查看了所有答案和评论之后,我将通过一些代码来总结它们,以测试隐式和显式等待的同时使用。

  • 仅当您(通常)不需要检查是否缺少元素时(例如在废弃的Web抓取项目中),才使用隐式等待。

  • 切勿将隐式等待和显式等待混合在一起。请参阅link1link2。如果测试是否缺少元素,那么等待时间将变得不可预测。在下面的代码中,仅有时等待时间=隐式等待。您只需使用无效的定位器即可测试是否缺席。

我已将link2中的代码进行了重构,使其简短并提供了摘要。该代码显示了同时使用隐式和显式等待时的实际等待时间。

下面的代码进入网站,并尝试查找有效元素和无效元素。它同时使用隐式和显式等待。如果元素搜索无效,它将尝试使用不同的隐式/ IW和显式/ EW等待时间组合-IW = EW,IW> EW和IW

首先,输出:

WHEN ELEMENT IS FOUND WITHOUT ANY DELAY :
>>> WITH implicit = 30, explicit = 20  :::::  Wait time = 0


WHEN ELEMENT IS NOT FOUND :
a. When implicit wait = explicit wait.
>>> WITH implicit = 10, explicit = 10  :::::  Wait time = 10. ***WITH EXCEPTION*** : NoSuchElementException

b. When implicit wait > explicit wait.
>>> WITH implicit = 30, explicit = 10  :::::  Wait time = 30. ***WITH EXCEPTION*** : NoSuchElementException

c. When implicit wait < explicit wait.
>>> WITH implicit = 10, explicit = 30  :::::  Wait time = 10. ***WITH EXCEPTION*** : NoSuchElementException

代码:

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

/*
 * Facing this chromedriver error after opening browser - [SEVERE]: Timed out receiving message
 * from renderer: 0.100.
 * */
public class TimeTest {
    static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");
    static final String URL = "https://www.redbus.in/";
    static final String TIME_ZONE_NAME = "Europe/Madrid";
    static final By validLoc = By.id("src");
    static final By inValidLoc = By.id("invalid locator");
    static WebDriver driver;

        public static void main(String[] args) {
            dateFormat.setTimeZone(TimeZone.getTimeZone(TIME_ZONE_NAME));

            //>>> Open chrome browser
            System.setProperty("webdriver.chrome.driver", "C:/drivers/chromedriver.exe");
            TimeTest.driver= new ChromeDriver();
            driver.manage().window().maximize();

            //>>> Test waiting logic.

            System.out.println("\n\nWHEN ELEMENT IS FOUND WITHOUT ANY DELAY : ");
            //mixing of implicit wait and explicit wait will not impact on webdriver behavior.
            testWait(30, 20, validLoc, "");

            System.out.println("\n\nWHEN ELEMENT IS NOT FOUND : ");
            //Run the method multiple times. Wait time generally = 10 seconds, but sometimes = 20 seconds.
            testWait(10, 10, inValidLoc, "a. When implicit wait = explicit wait.");

            //Wait time always = implicit wait. Generally ?
            testWait(30, 10, inValidLoc, "b. When implicit wait > explicit wait.");

            //Wait time always = implicit wait. Generally ?
            testWait(10, 30, inValidLoc, "c. When implicit wait < explicit wait.");

            //>>> Close the browser.
            driver.quit();
        }


        public static void testWait(int implicitWait, int explicitWait, By locator, String comment){
            // setting implicit time
            driver.manage().timeouts().implicitlyWait(implicitWait, TimeUnit.SECONDS);

            // Loading a URL
            driver.get(URL);

            // defining explicit wait
            WebDriverWait wait= new WebDriverWait(driver, explicitWait);
            // Locating and typing in From text box.


            Date start = new Date();
            String waitStats = comment + "\n>>> WITH implicit = " + implicitWait + ", explicit = " + explicitWait +
                    "  :::::  " ;//+ "Wait start = " + dateFormat.format(start)

            String exceptionMsg = "";

            try {
                WebElement fromTextBox = wait.until(ExpectedConditions.visibilityOf(driver.findElement(locator)));
            }catch (Exception ex){
                exceptionMsg = ". ***WITH EXCEPTION*** : " + ex.getClass().getSimpleName();
            }

            Date end = new Date();
            //waitStats += ", Wait end = " + dateFormat.format(end)
            waitStats += "Wait time = " +
                    TimeUnit.SECONDS.convert(end.getTime() - start.getTime(), TimeUnit.MILLISECONDS)
                    + exceptionMsg + "\n";

            System.out.println(waitStats);

        }

}

答案 7 :(得分:0)

隐式等待:

  1. 适用于所有driver.findelement命令
  2. 仅关心元素的存在。如果元素是不可见的或不可交互的,那么它将不会在意。

明确等待

  1. 您可以检查状态,可见性,交互性和许多其他内容-动态等待这些

    WebDriverWait等待=新的WebDriverWait(driver,Duration.ofSeconds(20)); wait.until(ExpectedConditions.presenceOfElementLocatedBy(By.id(“ xcxcxc”)))