在自动化测试过程中必然会遇到环境不稳定、网络加载缓慢等情况。当定位没有问题,但程序运行时却报出元素不存在(不可见)的错误时,就需要思考是否是因为程序运行太快或者页面加载太慢而造成了元素不可见,此时就必须设置等待时间,直到元素可见后再继续运行程序。
当UI自动化页面元素不存在时,常见的发生异常的原因有如下几点:
·页面加载时间过慢,需要查找的元素代码已经执行完成,但是页面还未加载成功,从而发生异常;
·查到的元素没有在当前的iframe或者frame中,此时需要切换至对应的iframe或者frame中;
·代码中对元素的描述错误。
强制等待
强制等待也叫作固定休眠时间,是设置等待的最简单的方法,如sleep(5),其中5的单位为s
sleep(*)不管什么情况代码运行到它所在的位置时,都会让脚本暂停运行一定时间(如sleep(5)为暂停5s),时间到达后再继续运行。
sleep()的缺点是不够智能,如果设置的时间太短,而元素还没有加载出来,代码照样会报错;如果设置的时间太长,则又会浪费时间。不要忽视每次几秒的时间,当用例多了,代码量大了,多几秒就会影响脚本的整体运行速度,所以应尽量少用强制等待sleep()(至少生产环境中尽量避免使用)。
隐式等待
隐式等待也叫作智能等待(implicitly_wait(xx)),当设置了一段时间后,在这段时间内如果页面完成加载,则进行下一步,如果未加载完,则会报超时错误。
设置隐式等待(implicitly_wait())后,如果整个页面很快加载完毕,而因为程序代码中对元素的描述属性不正确,造成不能在页面中很快找到该元素时,代码会根据隐式等待时设置的一个最长等待时间(如implicitly_wait(10),最长等待时间等于10s),不断地尝试查找元素,直到超过最长等待时间(10s)后才会抛出异常,告知找不到该元素。因此,隐式等待中的最长等待时间也可理解为查找元素的最长时间。
隐式等待(implicitly_wait())也是存在缺点的。隐式等待是设置了一个最长等待时间(implicitly_wait(10),最长等待时间等于10s),如果在规定时间内(10s以内)网页很快加载完成(如5s),则执行下一步,否则一直等到时间(10s)截止,然后才执行下一步。这里就存在弊端了,例如有时程序代码中想要操作的页面中的某个元素早就加载完成了,但是显示过程中如JS等代码加载特别慢,整个网页还处在加载过程中,那么程序代码会一直等待整个页面加载完成才会执行下一步。
from selenium imsport webdriver
from selenium.common.exceptions import NoSuchElementException
import time
driver = webdriver.Chrome()
# implicitly_wait隐式等待
# 判断某元素,如果超过10s未发现,则s抛出异常# 如果在5s内页面加载完毕,则对该元素进行操作
driver.implicitly_wait(10)
driver.get("https://cn.bing.com/")
try:
print(time.ctime())
#输出第一个时间
# 情况1:正确的搜索框元素定义id='sb_form_q'
# ======运行情况1时,需要将情况2的代码注释掉======
driver.find_element_by_xpath("//*[@id='sb_form_q']").send_keys("selenium")
driver.find_element_by_xpath("//*[@id='sb_form_go']").click()
# 情况2:将输入框id改为sb_form_qq,看看时间是否等待了10s后,才抛出异常
# ======运行情况2时,需要将情况1的代码注释掉======
driver.find_element_by_xpath("//input[@id='sb_form_qq']").send_keys("selenium")
driver.find_element_by_xpath("//input[@id='sb_form_go']").click()
except NoSuchElementException as e:
print(e)
finally:
print(time.ctime())
# 输出第一个时间,观察间隔时间
driver.quit()
情况1:两次运行的时间几乎相同,运行结果如下:
Wed Jun 2 11:38:05 2021
Wed Jun 2 11:38:07 2021
情况2:两次运行的时间相差10s,运行结果如下:
Wed Jun 2 11:38:59 2021
Message: no such element: Unable to locate element: {"method":"xpath","selector":"//*[@id='sb_form_qq']"}
(Session info: chrome=91.0.4472.77)
(Driver info: chromedriver=72.0.3626.69 (3c16f8a135abc0d4da2dff33804db79b849a7c38),platform=Windows NT 10.0.16299 x86_64)
Wed Jun 2 11:39:10 2021
注:隐式等待对整个Driver的周期都会起作用,所以只需要设置一次即可,就是在整个程序代码中的最前面设置一次即可。
显式等待
显式等待(WebDriverWait)配合该类的until()和until_not()方法,能够根据判断条件进行灵活地等待。它的执行原理是:程序每隔多长时间检查一次,如果条件成立了,则执行下一步,否则继续等待,直到超过设置的最长时间,然后抛出TimeoutException。
在使用WebDriverWait方法前需要导入该方法。使用WebDriverWait方法时常常会结合expected_conditions模块一起使用。
from seleniumimport webdriver
from selenium.webdriver.common.byimport By
from selenium.webdriver.support.uiimport WebDriverWait
from selenium.webdriver.supportimport expected_conditionsas EC
driver = webdriver.Chrome()
driver.get("https://cn.bing.com/")
#driver.find_element_by_xpath("//*[@id='sb_form_q']")
element = WebDriverWait(driver,5,0.5).until(EC.presence_of_element_located((By.ID,"sb_form_q")))
element.send_keys("selenium")
driver.close()
WebDriverWait类是WebDriver提供的等待方法,具体格式如下:
WebDriverWait(driver,timeout=0.5,poll_frequency=0.5,ignored_exceptions=None)
WebDriverWait方法中的参数说明如下:
·driver:传入WebDriver实例,即代码中的driver。
·timeout:超时时间,即等待的最长时间(同时要考虑隐式等待时间)。
·poll_frequency:调用until或until_not中的方法的间隔时间,默认是0.5s。
·ignored_exceptions:忽略的异常。如果在调用until或until_not的过程中抛出这个元组中的异常,则不中断代码,继续等待;如果抛出的是这个元组外的异常,则中断代码,抛出异常。默认只有NoSuchElementException。
WebDriverWait需要与until()或者until_not()方法结合使用。例如:
WebDriverWait(driver,5,0.5).until(method,message=" ")
调用该方法提供的驱动程序作为参数,直到返回值为True。·method:在等待期间,每隔一段时间调用这个传入的方法,直到返回值不是False。·message:如果超时,抛出TimeoutException,将message传入异常。如下:
WebDriverWait(driver,5,0.5).until_not(method,message=" ")
调用该方法提供的驱动程序作为参数,直到返回值为False。·until_not与until相反,until是当某元素出现或某个条件成立则继续执行,until_not是当某元素消失或某个条件不成立则继续执行,两者参数相同。
expected_conditions模块包含十几个condition,与until、until_not组合能够实现很多判断,如果将其灵活封装,可以大大提高脚本的稳定性。
·title_is:判断当前页面的标题是否完全等于预期字符串,返回布尔值。
·title_contains:判断当前页面的标题是否包含预期字符串,返回布尔值。
·presence_of_element_located:判断某个元素是否被加到了DOM树里,并不代表该元素一定可见。
·visibility_of_element_located:判断某个元素是否可见。可见代表元素非隐藏,并且元素的宽和高都不等于0。
·visibility_of:跟前面的几个方法做一样的事情,只是前面的方法要传入locator,而该方法直接传定位到的element即可。
·presence_of_all_elements_located:判断是否至少有一个元素存在于DOM树中。例如,如果页面上有n个元素的class都是'b_searchbox',那么只要有一个元素存在,这个方法就返回True。
·text_to_be_present_in_element:判断某个元素中的text是否包含预期的字符串。
·text_to_be_present_in_element_value:判断某个元素中的value属性是否包含预期的字符串。
·frame_to_be_available_and_switch_to_it:判断该frame是否可以切换(switch)进Frame,如果可以的话则返回True并且切换进去,否则返回False。
·invisibility_of_element_located:判断某个元素是否不存在于DOM树中或不可见。
·element_to_be_clickable:判断某个元素是否可见并且是可以单击的。·staleness_of:当某个元素从DOM树中移除后,返回True或False。
·element_to_be_selected:判断某个元素是否被选中了,一般用在下拉列表框中。
·element_selection_state_to_be:判断某个元素的选中状态是否符合预期。
·element_located_selection_state_to_be:跟前面的方法作用一样,只是前面的方法传入定位到的element,而该方法传入locator。
·alert_is_present:判断页面上是否存在alert。
网友评论