常用的等待方式有4种:
线程等待
利用线程设置固定等待时间,直接粗暴费时。
Thread.sleep(1000);
隐式等待方式(Implicit Wait)
从该行代码起到webdriver退出,为期间的页面元素查找设置一个超时时间。在此时间段内,Selenium会不断地尝试查找该元素,超时失败后才抛出NoSuchElementException。当没有设置默认等待时,Selenium不会作任何等待。
driver.manage().timeouts().implicitlyWait(second, TimeUnit.SECONDS);
显示等待方式(Explicit Wait)
就是在给定的等待时间之内,没有符合给定条件,就抛出TimeoutException。
另外,当调用isEnable(), isDisplayed(), isSelected()这些判定方法,然而元素不存在时,会抛出NoSuchElementExpception异常。
Step 1, 声明WebDriverWait变量
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10)
Step 2, 使用ExpectedConditions中定义的条件设置等待条件。
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("username")));
driver.findElement(By.id("username")).sendKeys("HelloWorld");
除使用ExpectedConditions内定义的条件外,还可以自定义条件:
WebElement element = (new WebDriverWait(webdriver, 10)).until(new ExpectedCondition<WebElement>() {
@Override
public WebElement apply(WebDriver wd) {
return
wd.findElement(By.partialLinkText("www.seleniumhq.org/"));
}
});
这里有一个疑问就是: apply这个函数是干嘛的?
apply函数继承自com.google.common.base.Function接口。接口定义:
http://www.boyunjian.com/javadoc/com.ning.billing/killbill-osgi-bundles-analytics/0.2.2/_/com/google/common/base/Function.html
里面写到,这个函数是把其实现应用到输入参数当中,并返回处理结果。这里而until函数来自FluentWait类,作用是重复应用该实例(这里指WebDriverWait)的输入值(WebDriver)到给定的函数(apply)直到满足条件、抛出异常的情况。
流畅等待 Fluent Wait
我们可以从下面的代码中看到,对每个流畅等待实例,我们可以设置最大等待时间、条件检查间隔、需要忽略的异常,当然还有等待条件。这个与显式等待非常相似。WebDriverWait继承了FluentWait<WebDriver>。FluentWait可以设置检查间隔,WebDriverWait更简便。
// Waiting 30 seconds for an element to be present on the page, checking
// for its presence once every 5 seconds.
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, SECONDS)
.pollingEvery(5, SECONDS)
.ignoring(NoSuchElementException.class);
WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.id("foo"));
}
});
隐式与显式等待的使用场合
不要混合用显式与隐式等待。因为隐式等待经常是在驱动端(如IEDriverServer.exe、ChromeDriver.exe等)和WebDriver server(selenium-server-standalone.jar)上实现的。而显式等待只在语言包(如selenium-java.jar)上实现。当把它们混合使用的时候,得到的是一种不确定的行为,而且这种行为还可能因为驱动端的改变而改变。当使用RemoteWebDriver或Grid的时候,情况会变得更加复杂。所以,当一个元素查找失败时,程序可能会因此遇到长期或一直等待的等情况。
参考文章:
https://stackoverflow.com/questions/15164742/combining-implicit-wait-and-explicit-wait-together-results-in-unexpected-wait-ti/15174978#15174978
官方文章也有相关警告:
http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp#explicit-and-implicit-waits
一篇更直接的。。。使用显式等待,忘记隐式等待的存在 LOL:
https://stackoverflow.com/questions/10404160/when-to-use-explicit-wait-vs-implicit-wait-in-selenium-webdriver
总结来讲就是:隐式等待功能有限(只能作用于等待元素),行为没有文档正式写明而且依赖于浏览器方的实现(也就是不可靠)。此文章中也有作者总结的使用情形:
Explicit wait:
- 有文档说明的已定义的操作。
- 运行在Selenium的本地部分(在你的代码里)。
- 在任何你能想到的情况下。
- 返回成功或timeout错误。
- 定义元素不存在为成功条件时。
- 自定义尝试间的等待时间和忽略的异常。
Implicit wait:
- 没有文档说明的,特别是没有定义的行为。
- 运行在Selenium远程端的部分(控制浏览器的部分)。
- 只用在findElement方法。
- 返回元素是否找到时。
- 测试时如果找不到元素都必须等待直到超时时。
- 不能被自定义时。
Tips
每个操作默认等待时间:5分钟