隐式等待和显式等待 Selenium 语法
⚡ 智能摘要
Selenium 等待命令将自动化脚本与动态页面行为同步,防止因元素异步加载而导致的测试失败。本参考文档解释了 WebDriver 语法中的隐式、显式和流畅等待策略,并阐述了它们的工作原理。 Java 代码示例,以及关于选择合适的等待时间以实现稳定、可靠的测试执行的实用指导。
In Selenium“等待”在执行可靠测试中扮演着重要角色。在本教程中,您将学习隐式等待命令和显式等待命令的关键方面和区别。 Selenium以及 Fluent Wait 的实际应用。
为什么我们需要等待 Selenium?
大多数现代 Web 应用程序都是使用以下方式开发的: 阿贾克斯 和 JavaScript当浏览器加载页面时,我们想要交互的元素可能会在不同的时间间隔内加载完毕。
这不仅使元素识别变得困难,而且如果未能及时找到该元素, Selenium 会扔一个 元素不可见异常. Selenium 等待机制通过给 WebDriver 一个确定的时间窗口来解决同步问题,在该窗口内,WebDriver 会查找元素,否则就会失败。
考虑这样一种场景:在同一个测试中同时使用了隐式等待和显式等待。假设隐式等待设置为 20 秒,显式等待设置为 10 秒。
如果我们正在寻找受某些因素支配的元素 预期条件 如果使用显式等待,且目标元素不在 10 秒的显式等待时间内,WebDriver 将回退到 20 秒的隐式等待时间,然后抛出异常。 元素不可见异常.
Selenium WebDriver 等待
- 隐式等待
- 显式等待
- 流利的等待
隐式等待 Selenium
此 隐式等待 Selenium 指示 WebDriver 在抛出 NoSuchElementException 异常之前等待一段设定的时间。默认值为 0。配置完成后,WebDriver 会在该时间段内轮询 DOM,如果等待时间过长则抛出异常。 Selenium WebDriver 继承了隐式等待的概念。 Watir.
在下面的示例中,我们声明了一个持续时间为 10 秒的隐式等待。如果元素不在该等待时间内,则会引发异常。
隐式等待语法(Selenium 4):
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
package guru.test99;
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.Test;
public class AppTest {
protected WebDriver driver;
@Test
public void guru99tutorials() throws InterruptedException {
driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
String eTitle = "Demo Guru99 Page";
String aTitle = "";
// launch Chrome and redirect it to the Base URL
driver.get("https://demo.guru99.com/test/guru99home/");
// Maximize the browser window
driver.manage().window().maximize();
// get the actual value of the title
aTitle = driver.getTitle();
// compare the actual title with the expected title
if (aTitle.equals(eTitle)) {
System.out.println("Test Passed");
} else {
System.out.println("Test Failed");
}
// close browser
driver.close();
}
}
的解释 Code
在上述例子中,请考虑以下陈述:
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
Selenium 版本 4 将旧的双参数签名(整数加 TimeUnit)替换为单个 Duration 参数。Duration 类支持秒、分钟、毫秒以及其他时间单位,并通过静态辅助方法(例如 Duration.ofSeconds、Duration.ofMillis 和 Duration.ofMinutes)来实现。
明确等待 Selenium
此 明确等待 Selenium 指示 WebDriver 在抛出 ElementNotVisibleException 异常之前,等待特定条件(预期条件)或达到最大持续时间。这种等待方式更智能,因为它仅应用于指定的元素。当测试需要处理动态加载的 Ajax 内容时,显式等待优于隐式等待。
一旦声明了显式等待,就必须使用 预期条件或者,您可以使用以下方式配置轮询频率 流利的等待。 避免使用 线程.sleep()因为它会无条件地暂停执行,通常被认为是一种不良做法。
在下面的示例中,我们创建了一个引用 网络驱动程序等待 类,用以下方式实例化它 网络驱动程序 参考,并配置最大窗口时间为 20 秒。
显式等待语法(Selenium 4):
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(20));
package guru.test99;
import java.time.Duration;
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 org.testng.annotations.Test;
public class AppTest2 {
protected WebDriver driver;
@Test
public void guru99tutorials() throws InterruptedException {
driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(20));
String eTitle = "Demo Guru99 Page";
String aTitle = "";
// launch Chrome and redirect it to the Base URL
driver.get("https://demo.guru99.com/test/guru99home/");
// Maximize the browser window
driver.manage().window().maximize();
// get the actual value of the title
aTitle = driver.getTitle();
// compare the actual title with the expected title
if (aTitle.contentEquals(eTitle)) {
System.out.println("Test Passed");
} else {
System.out.println("Test Failed");
}
WebElement guru99seleniumlink;
guru99seleniumlink = wait.until(ExpectedConditions.visibilityOfElementLocated(
By.xpath("/html/body/div[1]/section/div[2]/div/div[1]/div/div[1]/div/div/div/div[2]/div[2]/div/div/div/div/div[1]/div/div/a/i")));
guru99seleniumlink.click();
}
}
的解释 Code
考虑以下代码:
WebElement guru99seleniumlink;
guru99seleniumlink = wait.until(ExpectedConditions.visibilityOfElementLocated(
By.xpath("/html/body/div[1]/section/div[2]/div/div[1]/div/div[1]/div/div/div/div[2]/div[2]/div/div/div/div/div[1]/div/div/a/i")));
guru99seleniumlink.click();
在这个 WebDriverWait 示例中,脚本最多会等待 20 秒,这是由以下代码定义的: 网络驱动程序等待 直到课堂结束 预期条件 无论哪个先发生,双方都感到满意。
以上 Java 代码最多等待 20 秒以符合条件。 元素定位可见性 是真实的。
以下预期条件可用于 Selenium 显式等待:
- 警报是否存在()
- 元素选择状态要成为()
- 可点击元素()
- 要选择的元素()
- 帧可用并切换到它()
- 元素位置的不可见性()
- 元素与文本的不可见性()
- presenceOfAllElementsLocatedBy()
- presenceOfElementLocated()
- 元素中要出现的文本()
- 元素定位中出现的文本()
- 元素值中要出现的文本()
- 标题是()
- 标题包含()
- 可见性()
- 可见性所有元素 ()
- 可见性所有元素定位于 ()
- 元素定位可见性()
流畅等待 Selenium
此 流畅等待 Selenium Fluent Wait 定义了 WebDriver 等待某个条件的最大持续时间,以及在抛出 ElementNotVisibleException 之前验证该条件的轮询频率。Fluent Wait 会定期检查元素,直到找到该对象或超时为止。
频率: 定期评估病情的重复周期。
设想这样一种场景:某个元素的加载时间无法预测,可能需要 10 秒、20 秒甚至更长时间。如果我们显式地设置 20 秒的等待时间,脚本会一直等待到超时才会失败。在这种情况下,Fluent Wait 是理想的选择,因为它会按照指定的频率轮询,直到找到目标元素或最终的计时器超时为止。
流畅等待语法(Selenium 4):
Wait<WebDriver> wait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(30))
.pollingEvery(Duration.ofSeconds(5))
.ignoring(NoSuchElementException.class);
旧版签名(接受整数值加上 TimeUnit)已被弃用。 Selenium 3.11 并已移除 Selenium 4. 上面所示的基于持续时间的 API 是目前推荐的方法。
package guru.test99;
import java.time.Duration;
import java.util.NoSuchElementException;
import java.util.function.Function;
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.FluentWait;
import org.openqa.selenium.support.ui.Wait;
import org.testng.annotations.Test;
public class AppTest3 {
protected WebDriver driver;
@Test
public void guru99tutorials() throws InterruptedException {
String eTitle = "Demo Guru99 Page";
String aTitle = "";
driver = new ChromeDriver();
// launch Chrome and redirect it to the Base URL
driver.get("https://demo.guru99.com/test/guru99home/");
// Maximize the browser window
driver.manage().window().maximize();
// get the actual value of the title
aTitle = driver.getTitle();
// compare the actual title with the expected title
if (aTitle.contentEquals(eTitle)) {
System.out.println("Test Passed");
} else {
System.out.println("Test Failed");
}
Wait<WebDriver> wait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(30))
.pollingEvery(Duration.ofSeconds(5))
.ignoring(NoSuchElementException.class);
WebElement clickseleniumlink = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.xpath("/html/body/div[1]/section/div[2]/div/div[1]/div/div[1]/div/div/div/div[2]/div[2]/div/div/div/div/div[1]/div/div/a/i"));
}
});
// click on the selenium link
clickseleniumlink.click();
// close browser
driver.close();
}
}
的解释 Code
考虑以下代码:
Wait<WebDriver> wait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(30))
.pollingEvery(Duration.ofSeconds(5))
.ignoring(NoSuchElementException.class);
在上面的例子中,我们声明了一个 Fluent Wait,超时时间为 30 秒,轮询频率为 5 秒,并忽略 没有这样的元素异常.
考虑以下代码:
public WebElement apply(WebDriver driver) {
return driver.findElement(By.xpath("/html/body/div[1]/section/div[2]/div/div[1]/div/div[1]/div/div/div/div[2]/div[2]/div/div/div/div/div[1]/div/div/a/i"));
}
此函数用于识别页面上的 WebElement(此处为 WebElement)。 Selenium 首页链接)。轮询间隔为 5 秒,超时时间为 30 秒,等待过程每 5 秒检查一次元素,最多持续 30 秒。如果元素在该时间窗口内,脚本继续执行。否则, 元素不可见异常 被抛出。
另请检查: Selenium IDE 初学者教程
隐式等待与显式等待之间的区别
下表重点列出了隐式等待和显式等待之间的主要区别。 Selenium.
| 隐式等待 | 显式等待 |
|---|---|
| 隐式等待时间应用于脚本中的所有元素。 | 显式等待时间仅应用于特定目标元素。 |
| 在隐式等待中,未为元素指定 ExpectedConditions。 | 在显式等待中,必须为元素定义 ExpectedConditions。 |
| 建议在元素加载于配置的隐式等待窗口内时使用。 | 建议在元素加载时间较长以及验证元素状态(例如 visibilityOfElementLocated、elementToBeClickable 或 elementToBeSelected)时使用。 |
| 设置一次,即可应用于 WebDriver 实例的整个生命周期。 | 按元素或按检查项设置,提供更精细的控制。 |
如何选择合适的等待策略
选择正确的等待命令会直接影响脚本的稳定性和执行时间。请使用此决策框架为每种场景选择合适的选项。
- 确定负荷模式: 检查元素是在固定时间、Ajax 响应后还是以不可预测的时间间隔出现。固定加载时间适合使用隐式等待 (Implicit Wait),而不可预测的加载时间则需要使用流畅等待 (Fluent Wait)。
- 避免混用隐式等待和显式等待: 将两者结合起来可能会造成意想不到的延误,因为较长的等待时间可能会占据主导地位。 Selenium 文档建议每个 WebDriver 会话只使用一种策略。
- 默认设置为显式等待动态内容: 当页面依赖于 Ajax、条件渲染或动画时,使用 ExpectedConditions 的显式等待可以精确地定位到重要的元素。
- 使用 Fluent Wait 实现可变时序: 当元素加载时间在不同运行之间变化时,请为 Fluent Wait 配置轮询间隔。与单次长时间超时相比,轮询可以减少总等待时间。
- 替换 Thread.sleep: 硬编码的睡眠操作会降低测试套件的运行速度,并掩盖真正的时序问题。应将其替换为条件等待,以保持执行速度快且结果确定。
- 调整超时值: 开始时设置较短的超时时间(5-10 秒),只有当故障表明负载确实缓慢时才增加超时时间。过长的默认超时时间会掩盖性能下降的问题。
- 在辅助工具中保留等待时间: 将等待逻辑集中在一个辅助类中,以便超时策略的更改能够应用于整个测试套件。
遵循这一框架,自动化工程师可以构建能够适应实际应用程序时间安排的弹性脚本,而不会变得缓慢或脆弱。
避免常见错误 Selenium 等待
即使是经验丰富的测试人员,在使用过程中也会陷入一些反复出现的陷阱。 Selenium 等待。避免这些问题可以保证脚本运行快速、稳定,并且易于跨团队和环境维护。
第一个常见的错误是过度使用 `Thread.sleep`。硬编码的暂停会强制脚本等待完整的等待时间,而不管元素是否实际可用,这会增加总运行时间。应该用 `Explicit Wait` 或 `Fluent Wait` 来替换这种暂停,以便脚本在满足条件后立即继续执行。
第二个错误是在同一个测试中混用隐式等待和显式等待。这两种机制会相互叠加,导致难以调试的不可预测的超时。每个 WebDriver 会话应选择一种策略并始终如一地应用。
第三个错误是“以防万一”地将超时时间设置得过长。过长的默认超时时间会掩盖真正的性能问题,并减慢持续集成管道中的反馈速度。应该从较短的超时时间开始,只有当故障日志证实存在真正的时序问题时才延长超时时间。
另请检查: Selenium 初学者教程:7 天学会 WebDriver

