等待是编写可靠且稳健的Selenium测试的关键部分。无论您是在处理动态内容、异步加载还是复杂的UI交互,了解并掌握不同的等待形式对于确保测试产生一致结果至关重要。
在本文中,我们将深入探讨Selenium 4中的各种等待方式,如隐式等待、显式等待和流畅等待方式。本文将为您在Selenium WebDriver 4中的等待需求提供一站式解决方案。此外,您还可以学习如何在Selenium WebDriver中等待API响应。
了解基本概念:隐式等待、显式等待和灵活等待
等待方式 | 定义 | 何时使用 |
---|---|---|
隐式等待 | 为整个WebDriver实例设置默认等待时间,这会影响所有元素的搜索。这是一种快速而简单的方式,可以处理不能立即获取的元素,但对于复杂的场景来说,这并不是最有效的方式。 | 无论页面的性质如何,都应使用这种方式。因为它可以为与页面的每次交互添加隐式等待,所以在理想情况下,必须为隐式等待条件添加几秒的等待超时时间。 |
显式等待 | 它允许您在满足等待特定条件后再继续。它比隐式等待更精确,但灵活性仍然有限。 | 当您想等待某个条件为真时,就应该使用此方式。例如,等待按钮在页面上可见后再点击它。 |
灵活等待 | 它是WebDriver Wait的一种更高级的方式,它能够定义自定义轮询间隔、指定要忽略的异常并创建复杂条件。它是Selenium中最强大、最灵活的等待方式选择。 | 它是显式等待的高级版本,具有更高的精度。它可以用于任何需要智能等待条件为真的动态页面。与显式等待不同,这种等待带有轮询策略,使其更加精确和智能。 |
灵活等待与显式等待有何不同?
对于常见的条件(如等待元素可点击、可见或存在),请使用显式等待。但当您需要对等待行为进行更高级的控制(如自定义轮询间隔、处理异常或组合多个条件)时,请使用灵活等待。
隐式等待示例:
`driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(30));`
显式等待示例:
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("submitButton"))
Selenium WebDriver 4中的灵活等待示例
Selenium 官方网站将等待方式列为浏览器自动化中最关键的方面之一。了解 Selenium WebDriver 4 中不同的灵活等待方式实现非常重要。
以下是WebDriver中各种灵活等待的示例,您可以有效地利用它们。
处理NoSuchElementException的灵活等待示例
代码解释
这段代码旨在等待一个元素(LoginBtn)使其变得既可见又可点击。它使用灵活等待来处理由于动态内容加载或延迟渲染而导致元素可能无法立即获取的情况。通过忽略 NoSuchElementException,代码避免了提前测试失败,确保只有在元素完全准备好后才与之进行交互。
在何时使用此方式?
在页面上尝试与尚未渲染的元素进行交互时,如预计出现“NoSuchElementException”异常,请使用此等待方式。
Wait<WebDriver> wait =
new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoSuchElementException.class);
wait.until(
d -> {
WebElement dynamicElement = driver.findElement(By.id("loginBtn"));
if (dynamicElement.isDisplayed() && dynamicElement.isEnabled()) {
dynamicElement.click();
return true;
}
return false;
});
处理NoSuchElementException和 StaleElementReferenceException 的灵活等待示例
代码解释:
本段代码旨在等待一个元素(loginBtn)使其变得既可见又可点击。它使用灵活等待来处理由于动态内容加载或延迟渲染导致元素可能无法立即获取的情况。此段代码可处理 NoSuchElementException 和 StaleElementReferenceException 这两种异常。
在何时使用此方式?
在尝试与尚未呈现的元素进行交互时,如预计会出现 NoSuchElementException或StaleElementReferenceException任何一种异常,请使用此等待方式。
Wait<WebDriver> wait =
new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoSuchElementException.class)
.ignoring(StaleElementReferenceException.class);
wait.until(
d -> {
WebElement dynamicElement = driver.findElement(By.id("loginBtn"));
if (dynamicElement.isDisplayed() && dynamicElement.isEnabled()) {
dynamicElement.click();
return true;
}
return false;
});
Selenium 4 中针对元素文本变化的灵活等待
代码解释
此段代码旨在等待一个元素(statusMessage)具有文本 “Complete”状态。它使用灵活等待方式处理由于动态内容加载、延迟渲染或包含不同的文本可能导致元素无法立即获取的情况。此段代码可处理 NoSuchElementException 和 StaleElementReferenceException 异常。
在何时使用此功能?
在页面上预计会出现NoSuchElementException或StaleElementReferenceException异常,同时对元素具有特定的文本值时,请使用此等待方式。当保存一个实体并等待文本确认将“Complete”状态更改为“Pending”状态时,此方式将非常有用。
```
```
```
Wait<WebDriver> wait =
new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofMillis(300))
.ignoring(NoSuchElementException.class)
.ignoring(StaleElementReferenceException.class);
wait.until(
d -> {
WebElement statusMessage = driver.findElement(By.id("statusMessage"));
String text = statusMessage.getText();
// Wait until the text changes to "Complete"
if (text.equals("Complete")) {
return true;
}
// Print the current status and continue waiting
System.out.println("Current status: " + text);
return false;
});
针对带有某个值下拉菜单的灵活等待示例
何时使用此方式?
当处理选项动态加载或选项可能无法立即获取的下拉菜单时,此灵活等待示例特别有用。通过在与下拉菜单交互之前等待特定值出现,您可以确保您的测试既可靠且不受计时问题的影响。
Wait<WebDriver> wait =
new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoSuchElementException.class);
wait.until(
d -> {
WebElement dropdown = driver.findElement(By.id("myDropdown"));
Select select = new Select(dropdown);
List<WebElement> options = select.getOptions();
for (WebElement option : options) {
if (option.getText().equals("Desired Value")) {
select.selectByVisibleText("Desired Value");
return true;
}
}
return false;
});
警告提示框消失的灵活等待示例
什么时候使用它?
当您想在警告提示框从页面消失后继续操作时,这个灵活等待示例特别有用。
Wait<WebDriver> wait =
new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(10))
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoAlertPresentException.class);
wait.until(
d -> {
try {
d.switchTo().alert().accept();
return false; // Alert is still present
} catch (NoAlertPresentException e) {
return true; // Alert has disappeared
}
});
多个条件相链接时的Fluent等待示例
什么时候使用它?
您需要与一个只能在以下情况之后才可点击的UI元素进行交互:
- 模态框内的一个按钮可以点击。
- 一个模态对话框出现。
- 模态框内的加载旋转图标消失。
Wait<WebDriver> wait =
new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(20))
.pollingEvery(Duration.ofMillis(500))
.ignoring(NoSuchElementException.class);
wait.until(driver -> {
WebElement modal = driver.findElement(By.id("modalWindow"));
if (!modal.isDisplayed()) return false;
WebElement spinner = modal.findElement(By.id("loadingSpinner"));
if (spinner.isDisplayed()) return false;
WebElement button = modal.findElement(By.id("confirmButton"));
if (!button.isEnabled()) return false;
button.click();
return true;
});
不同的等待方式如何影响测试执行时间?
测试执行时间直接受到所选择的等待方式的影响。例如,如果一个代码库有超过100个测试场景,每个场景都有10秒的睡眠超时,那么总执行时间将延迟1000秒——大约是16分钟。不适当的等待时间的影响比单纯累加超时时间更为复杂。如果睡眠超时是一个核心方法(如loadingHomePage)的一部分,并且在100个测试中多次加载主页,那么延迟可能会呈指数级增长。
如果一个测试套件需要多花费一个小时来提供反馈,这就会浪费大约13%的工作时间。这就是为什么适当的等待条件对于更快、更有效的反馈过程至关重要。
常见的陷阱
一个常见的陷阱是猜测等待时间,而不是尝试不同的值。人们通常在显式等待方式中使用固定的常量值,而不是使用灵活等待。使用固定的超时时间可能会使等待时间超过必要等待时间。
此外,等待UI元素并不是确保页面可交互的唯一方法。像Cypress和Playwright这样的工具提供了等待API响应等解决方案,这可以提供一种更有效的方式来确保准备就绪。如果您正在使用Selenium WebDriver,您也可以使用网络响应等待方式。
与其他工具的比较
Cypress提供了自动等待元素出现和操作完成的功能,减少了手动等待的需要。Playwright 同样支持内置的等待网络响应和元素状态,简化了同步。Selenium开发者是时候考虑在该工具中建立一个强大的等待机制了,无论是作为插件还是作为库方法。