繁体   English   中英

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

[英]When to use explicit wait vs implicit wait in 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()的代码也会更好吗?

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


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

显式等待:

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

隐式等待:

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

带解释的代码示例。 第一个隐式等待:

WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = driver.findElement(By.id("myDynamicElement"));

现在显式等待:

WebDriver driver = new FirefoxDriver();
driver.get("http://somedomain/url_that_delays_loading");
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement myDynamicElement = wait.until(
  ExpectedConditions.presenceOfElementLocated(By.id("myDynamicElement")));

两个代码示例都做同样的事情。 找到某个元素并在 10 秒后未找到则放弃。 隐式等待只能做到这一点。 它只能尝试找到超时的元素。 显式等待的优势在于它可以等待各种条件。 还可以自定义超时并忽略某些异常。

可能的条件numberOfElementsToBeMoreThanelementToBeClickablenumberOfElementsToBeMoreThaninvisibilityOf 以下是内置预期条件的列表: https : //seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html

更多解释:

隐式等待超时仅对findElement*方法有效。 如果设置,则所有findElement*将在声明无法找到元素之前“等待”设置的时间。

findElement*将如何等待。 这取决于浏览器或操作系统或 selenium 版本。 可能的实现是:

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

该列表是通过观察和阅读错误报告以及对 selenium 源代码的粗略阅读而收集的。


我的结论:隐式等待是不好的。 能力有限。 该行为未记录并依赖于实现。

显式等待可以完成隐式等待可以做的一切,甚至更多。 显式等待的唯一缺点是代码更冗长。 但是这种冗长使代码变得明确。 显式优于隐式。 对?


进一步阅读:

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

看到这个链接流畅的等待描述

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

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();

希望这对你有帮助)

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

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

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

您是否尝试过使用“ 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 :)

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

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

隐式等待:

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

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

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

何时使用隐式等待?

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

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

显式等待:

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

在 Java Selenium 中声明显式等待。

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

何时使用显式等待?

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

IE。 假设您设置了 5 秒的显式等待,驱动程序能够在 2 秒内识别 Web 元素,因为我们应用了显式等待驱动程序不会再等待 3 秒(直到 5 秒)。 驱动程序将在 2 秒后继续。 这将加快自动化过程。

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

句法:

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

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

句法:

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

在查看了此处的所有答案和评论后,我将用一些代码对其进行总结,以测试隐式和显式等待的同时使用。

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

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

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

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

首先,输出:

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);

        }

}

隐式等待:

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

显式等待

  1. 您可以检查是否存在、可见性、可交互性和许多其他内容 - 动态等待这些

    WebDriverWait wait = new WebDriverWait(driver,Duration.ofSeconds(20)); wait.until(ExpectedConditions.presenceOfElementLocatedBy(By.id("xcxcxc"));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM