这是一个在写自动化脚本时经常遇到的问题。试想这样的一个场景,通过脚本打开一个网页,可是由于网络的问题页面并没有及时加载进来,这时候如果已经运行到之后查找元素的代码那么势必会抛出错误找不到相应元素,而事实并非如此。如果没有合适的元素等待处理,这样的测试代码不仅不够健壮,过多的误报会消耗测试人员大量的精力去查找测试失败的原因。元素等待就是在指定的时间内等待元素加载进来之后再执行下面的代码,否则一直等待下去直到超过指定时间。
Selenium中一共有三种等待的方法,下面依次介绍一下。
1. sleep(seconds)
这是最傻的一种方式,也就是不管指定的元素是否加载进来,都等待指定的秒数。唯一的好处是写起来非常简单,个人在调试或者写demo的时候会这么做。坏处则是严重降低执行效率,页面元素明明已经加载了还在那儿傻等。当用例数量巨大的时候,每个用例多一秒的等待多会严重拖累整个测试集的运行效率。所以在正式的测试脚本中非万不得已不能使用这种方法。
2. webdriver.implicit_wait(seconds)
这是webdriver类里提供的一个方法,为这个session设置一个全局的等待时间。他的行为是在指定的时间内等待元素的加载,一旦找到了指定元素则立刻继续执行之后的代码。好处是显而易见的,提高了测试效率不在一味傻等。而且因为是全局的设置,不需要在之后的代码中再单独处理元素等待。所以这是最高效地处理元素等待的方式。
3.WebDriverWait及expected_conditions
这个方法使用起来相对方法二更复杂,只对指定的元素进行等待,相对可自己设定的参数也更多。WebDriverWait类一般配合其until()或until_not()方法使用。下面是官方文档对各参数的一些解释。个人觉得挺模糊的不好理解,这里说一下自己的理解。当使用WebDriverWait.until(method)则表示持续等待直到method方法返回true,然后返回method返回的对像。如果超过timeout时间则抛出timeout的exception。 not_until则是等待直到method方法返回false
WebDriverWait(driver, timeout,poll_frequency=0.5, ignored_exceptions=None).until(method,message='')
driver: 浏览器对象
timeout: 最长超时时间,以秒为单位
poll_frequency: 检测的间隔时间,以秒为单位,默认为0.5
ignored_exception: 包含异常类的可迭代结构,用来包含运行期间需要忽略的异常,默认只包含NoSuchElementException。这个怎么理解呢,就是在运行过程中如果抛出的异常在被包含在这个迭代中,那么异常不会抛出而是继续等待直到超过timeout的时间。
method: 浏览器对象提供的方法,一般配合expected_conditions类提供的方法来使用。
expected_conditions: 这个类提供了一系列判断元素状态的方法,例如元素是否存在,是否可见,是否被选中等等。详细的方法列表请参考官方文档。
下面举几个具体的例子来看怎么应用WebDriverWait来进行元素等待。
例子1等待直到百度搜索框加载
driver = webdriver.Firefox()
driver.get('http://www.baidu.com')
search_textbox= WebDriverWait(driver, 10, 0.5).until(expected_conditions.presence_of_element_located(By.ID, 'kw')
search_textbox.send_keys('selenium')
time.sleep(5)
search_textbox.clear()
这段code是等待百度的搜索框加载进来。这里有一点需要说明一下,因为presence_of_element_located方法在成功的时候会返回参数locator所指向的对象,所以这里直接返回了搜索框对象赋值给了search_textbox变量。但是expected_conditions中并不是所有的参数都返回元素对象,有的只返回布尔值。所以千万不要完全照抄,还需要了解自己调用的方法所返回的对象是什么。
例2等待直到百度搜索框可见
driver = webdriver.Firefox()
driver.get('http://www.baidu.com')
search_textbox= WebDriverWait(driver, 10, 0.5).until(expected_conditions.visibility_of_element_located(By.ID, 'kw')
search_textbox.send_keys('selenium')
time.sleep(5)
search_textbox.clear()
看上去跟前面的例子非常相似,这里强调一下presence_of_element_located()与visibility_of_element_located()的区别。前者只要搜索框加载到了DOM树里就返回了元素对象,而后者必须元素对象在页面上可见才返回。因为加载成功并不代表在页面上可见,请注意。
好了,Selenium元素等待的方法就全介绍完了。