58

我在用:

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()吗?

4

8 回答 8

116

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 秒后没有找到则放弃。隐式等待只能做到这一点。它只能尝试找到一个超时的元素。显式等待的优势在于它可以等待各种条件。还可以自定义超时并忽略某些异常。

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

更多解释:

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

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

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

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


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

显式等待可以做所有隐式等待可以做的事情,甚至更多。显式等待的唯一缺点是代码更冗长。但是这种冗长使代码变得明确。显式优于隐式。正确的?


进一步阅读:

于 2015-01-21T12:40:27.477 回答
4

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

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

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

于 2013-03-12T16:54:55.920 回答
4

你试过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();

希望这对你有帮助)

于 2012-09-03T13:24:21.340 回答
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 :)

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

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

于 2012-05-01T21:56:15.077 回答
1

隐式等待:

    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 秒后继续。这将加快自动化过程。

于 2017-05-16T18:15:35.537 回答
0

隐式等待:

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

显式等待

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

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

于 2020-08-18T11:17:26.680 回答
0

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

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

  • 切勿将隐式等待和显式等待混合在一起。请参阅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);

        }

}
于 2020-03-18T19:44:06.613 回答
0

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

句法:

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

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

句法:

WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver,30);
于 2017-08-08T06:13:44.417 回答