强制等待
因为有些元素还没加载出来就对其进行操作了,这样必然是无法成功的,所以我们加入等待时间来尽可能的不因为元素没加载出来而报错。
在自动化测试中,元素等待是必须要掌握的。因为在自动化测试中,必然会遇到环境不稳定、网络加载缓慢等情况。当觉得定位没有问题,但程序运行时却报了元素不存在(不可见)时,那就需要思考是否因为程序运行太快或者页面加载太慢而造成了元素不可见,必须要进行等待,直到元素可见程序再继续运行。
UI自动化页面元素不存在,异常发生的原因常见有如下几点:
页面加载时间过慢,需要查找的元素程序代码执行已经完成,但是页面还未加载成功,从而发生异常;
查到的元素没有在当前的iframe或者frame中。此时需要切换至对应的iframe或者frame中才行;
代码中对元素的描述错误。
而在Selenium中,三种常见的等待方式都有各自的优点或缺点,当我们掌握后,可以尝试针对不同的情况选择最优的等待方式。
强制等待
强制等待也叫固定休眠时间,是设置等待最简单的方法, sleep(5),其中5的单位为秒,这在前面章节中的案例代码经常见到。
sleep(*)不管什么情况,运行到代码中它所在的位置,都会让程序暂停运行一定时间(如sleep(5)为暂停5秒),时间过后继续运行。
sleep()缺点是不够智能,如果设置的时间太短,而元素还没有加载出来,代码照样会报错;设置的时间太长,则又会浪费时间。不要忽视每次几秒的时间,当case多了,代码量大了,多个几秒就会影响整体的运行速度了,所以尽量少用强制等待sleep()(至少生产环境尽量少用)。
使用强制等待sleep()的方法如下。
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.by import By
driver = webdriver.Firefox()
driver.get("http://cn.bing.com/")
driver.find_element(By.XPATH,"//*[@id='sb_form_q']").send_keys("bella")
driver.find_element(By.XPATH,"//*[@id='sb_form_go']").click()
sleep(1)
driver.quit()
隐性等待
隐形等待也可叫做智能等待(implicitly_wait(xx)),设置了一段时间后,在这段时间如果页面完成加载,才进行下一步,如果没加载完,会报超时错误。
设置隐形等待(implicitly_wait())后,如果整个页面很快加载完毕,而程序代码中对元素的描述属性不正确,造成不能在页面中很快找到该元素,代码会根据隐形等待是设置了一个最长等待时间(implicitly_wait(10),最长等待时间等于10),不断的尝试查找元素,直到当超过最长等待时间(10秒)后才会抛出异常告知找不到该元素。因此,隐形等待中的最长等待时间,也可理解为查找元素的最长时间。
隐形等待(implicitly_wait())也是存在缺点的。隐形等待是设置了一个最长等待时间(implicitly_wait(10),最长等待时间等于10),如果在规定时间内(10秒以内)网页很快加载完成(如5秒),则执行下一步,否则一直等到时间(10秒)截止,然后才执行下一步。这里就存在弊端了,有时候程序代码中想要操作页面中的某个元素早就加载完成了,但是显示过程中如js等代码加载特别慢,而整个网页还在加载过程中,程序代码还是会一直等待整个页面加载完成,才会执行下一步。
以bing搜索页,举例来理解隐形等待implicitly_wait()的应用,代码如下:
from selenium import webdriver
from Selenium.common.exceptions import NoSuchElementException
from time import sleep,ctime
driver = webdriver.Firefox()
# implicitly_wait隐式等待
# 判断某元素,如果超过10秒未发现,则抛出异常
# 如果在5秒内页面加载完毕,则对该元素进行那个操作
driver.implicitly_wait(10)
driver.get("http://cn.bing.com/")
try:
print(ctime()) #输出第1个时间
# 情况1:正确的搜索框元素定义id='sb_form_q'
# ======运行情况1时,需要将情况2的代码注释掉======
# driver.find_element_by_xpath("//input[@id='sb_form_q']").send_keys("bella")
# driver.find_element_by_xpath("//input[@id='sb_form_go']").click()
# 情况2:将输入框id改为sb_form_qq,观察时间上是否等待了10秒后,才抛出异常
# ======运行情况2时,需要将情况1的代码注释掉======
driver.find_element_by_xpath("//input[@id='sb_form_qq']").send_keys("bella")
driver.find_element_by_xpath("//input[@id='sb_form_go']").click()
except NoSuchElementException as e:
print(e)
finally:
print(ctime()) #输出第1个时间,观察间隔时间
driver.quit()
结果:
情况1:
由于bing搜索页整体加载速度很快,而搜素框元素代码中定义正确,所以代码运行很快结束,可以看到输出的两个时间几乎一致。
Fri Feb 28 00:19:28 2020
Fri Feb 28 00:19:28 2020
将搜索框元素的ID属性改为’sb_form_qq’,而bing搜索页上并不存在该元素,代码运行肯定会被报错。
情况2:
运行代码,在结果中观察到代码运行,检测元素的时间超过implicitly_wait(10)中的最长等待时间10秒后,会然后抛出了错误,且两次输出时间间隔也是10秒。
Fri Feb 28 00:22:41 2020
Message: Unable to locate element: //input[@id='sb_form_qq']
Fri Feb 28 00:22:51 2020
注:
需要特别说明的是:隐性等待对整个driver的周期都起作用,所以只要设置一次即可,就是在整个程序代码中,最前面设置1次即可。