1127UI自動化測試經驗分享-顯式等待(一)WebDriverWait類、until()方法
最近忙於其他事情,部落格就沒那麼多時間來寫。原本想先分享下三種等待方式,但是隱式等待我還有點不太懂。這次先分享顯式等待。
一)顯式等待 WebDriverWait()
顯示等待,是針對於某個特定的元素設定的等待時間。
原始碼:
POLL_FREQUENCY = 0.5 # How long to sleep inbetween calls to the method IGNORED_EXCEPTIONS = (NoSuchElementException,) # exceptions ignored during calls to the method class WebDriverWait(object): def __init__(self, driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None): """Constructor, takes a WebDriver instance and timeout in seconds. :Args: - driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote) - timeout - Number of seconds before timing out - poll_frequency - sleep interval between calls By default, it is 0.5 second. - ignored_exceptions - iterable structure of exception classes ignored during calls. By default, it contains NoSuchElementException only. Example: from selenium.webdriver.support.ui import WebDriverWait \n element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("someId")) \n is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).\ \n until_not(lambda x: x.find_element_by_id("someId").is_displayed()) """ self._driver = driver self._timeout = timeout self._poll = poll_frequency # avoid the divide by zero if self._poll == 0: self._poll = POLL_FREQUENCY exceptions = list(IGNORED_EXCEPTIONS) if ignored_exceptions is not None: try: exceptions.extend(iter(ignored_exceptions)) except TypeError: # ignored_exceptions is not iterable exceptions.append(ignored_exceptions) self._ignored_exceptions = tuple(exceptions)
通過註釋瞭解到:ignored_exceptions:呼叫方法時忽略的異常;poll_frequency:在呼叫方法之間睡多久;
init()方法需要傳參 driver、timeout、poll_frequency、ignored_exceptions;
driver:webdriver的驅動;
timeout:最長超時時間,預設以秒為單位;
poll_frequency:休眠時間(步長)的間隔,檢測間隔時間,預設0.5s;
ignored_exceptions: 超時後的異常資訊,預設情況下拋 “NoSuchElementException"異常;
在設定時間timeout內,每隔一段時間poll_frequency(預設0.5秒) 檢測一次當前頁面,元素是否存在,如果超過設定時間還檢測不到則丟擲異常ignored_exceptions,如果元素存在則立即反饋。
那要怎麼用呢?
看下官方的舉例:element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id(“someId”))
is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).until_not(lambda x: x.find_element_by_id(“someId”).is_displayed())
二)until()、until_not()
WebDriverWait 一般是配合until() 或 until_not()方法,就能夠根據判斷條件而靈活地等待了。主要的意思就是:程式每隔xx秒看一眼,如果條件成立了,則執行下一步;否則繼續等待,直到超過設定的最長時間,然後丟擲TimeoutException異常。
格式:
WebDriverWait(driver, timeout).until(method, message=’’)
WebDriverWait(driver, timeout).until_not(method, message=’’)
【until_not() 我沒用過,本篇就分享until()】
原始碼:
def until(self, method, message=''):
"""Calls the method provided with the driver as an argument until the \
return value is not False."""
screen = None
stacktrace = None
end_time = time.time() + self._timeout
while True:
try:
value = method(self._driver)
if value:
return value
except self._ignored_exceptions as exc:
screen = getattr(exc, 'screen', None)
stacktrace = getattr(exc, 'stacktrace', None)
time.sleep(self._poll)
if time.time() > end_time:
break
raise TimeoutException(message, screen, stacktrace)
def until_not(self, method, message=''):
"""Calls the method provided with the driver as an argument until the \
return value is False."""
end_time = time.time() + self._timeout
while True:
try:
value = method(self._driver)
if not value:
return value
except self._ignored_exceptions:
return True
time.sleep(self._poll)
if time.time() > end_time:
break
raise TimeoutException(message)
until(method,message=’’) 的註釋:Calls the method provided with the driver as an argument until the return value is not False 將驅動提供的方法作為引數呼叫,直到返回值不為False;
好繞啊,要瘋啦,
我覺得就是在說:呼叫method作為一個引數,直到返回值為True;
那這個引數(或者叫條件) value = method(self._driver) 到底是什麼,要怎樣用呢?
不妨回到起點,顯式等待到底是什麼?
顯式等待會讓WebDriver等待滿足一定的條件以後再進一步的執行。 這 滿足一定的條件 是不是value?我覺得 就是。
在自動化測試中,最基本的、最重要的 要滿足的條件就是查詢到元素,find element;
所以value 應該可以寫成driver.find_element(),對吧?
def test_56(self):
""" 可執行方法method引數,很多人傳入了WebElement物件 這是錯誤的"""
from selenium.webdriver.support.wait import WebDriverWait
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.implicitly_wait(5)
self.driver.get("https://www.baidu.com")
WebDriverWait(self.driver, 10).until(self.driver.find_element_by_id('kw')) # 錯誤
time.sleep(2)
self.driver.quit()
但 報錯了。
File "D:\oss_1\Common\yidu.py", line 3900, in test_56
WebDriverWait(self.driver, 10).until(self.driver.find_element_by_id('kw')) # 錯誤
File "C:\Users\admin\AppData\Local\Programs\Python\Python36-32\lib\site-packages\selenium\webdriver\support\wait.py", line 71, in until
value = method(self._driver)
TypeError: 'WebElement' object is not callable
說的是 ‘WebElement’ object is not callable;所以 這裡的引數一定要是可以呼叫的,即這個物件一定有 call() 方法,否則會丟擲異常。
如何處理呢? 一般採用匿名函式lambda 。
lambda driver:driver.find_element(<定位元素>)
【當定位到元素時返回為WebElement,找不到元素時為顯式等待 報錯】(這兒後面會繼續深入分享)
def test_57z3(self):
from selenium.webdriver.support.wait import WebDriverWait
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.baidu.com")
print('0', time.ctime())
# TypeError: 'WebElement' object is not callable
try:
WebDriverWait(driver, 10).until(driver.find_element_by_id('kw'), '失敗')
except Exception as e11:
print(e11)
print('1', time.ctime())
# 成功
try:
WebDriverWait(driver, 10).until(lambda the_driver: the_driver.find_element_by_id('kw'), '失敗')
except Exception as e33:
print(e33)
print('3', time.ctime())
time.sleep(1)
driver.quit()
這個用例就說明了 顯式等待和until()結合後,可以智慧查詢元素;但是在web中有些元素是隱藏的,確實是存在;只不過不顯示,那就不方便執行操作,要怎麼做一個可以判斷元素顯示與否的顯式等待呢?
用WebElement的 is_displayed() 、is_enabled()、is_selected() 方法
WebDriverWait(driver, 10).until(lambda the_driver: the_driver.find_element_by_id(‘kw’).is_displayed())
def test_57z5(self):
from selenium.webdriver.support.wait import WebDriverWait
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.get("https://www.12306.cn/index/")
print('開始', time.ctime())
# <input id="toStation" type="hidden" value="" name="to_station">
# 這個元素預設是隱藏的
# selenium.common.exceptions.TimeoutException: Message: 失敗
try:
WebDriverWait(self.driver, 10).until(lambda the_driver: the_driver.find_element_by_id('toStation').is_displayed(), '失敗')
except Exception as e33:
print(e33) # 顯式等待的10秒 Message: 失敗
print('0', time.ctime())
# 成功
try:
WebDriverWait(self.driver, 10).until(lambda the_driver: the_driver.find_element_by_id('toStation'), '失敗')
except Exception as e33:
print(e33)
print('1', time.ctime())
time.sleep(1)
self.driver.quit()
結果很明顯:
Launching unittests with arguments python -m unittest yidu.Test_yidu.test_57z5 in D:\oss_1\Common
開始 Tue Nov 27 10:12:12 2018
Message: 失敗
0 Tue Nov 27 10:12:23 2018
1 Tue Nov 27 10:12:23 2018
Ran 1 test in 21.744s
OK
所以一種很簡單的 把元素查詢作為條件的 顯式等待就出來了,這是可以直接用到自動化指令碼中。起碼比起強制等待time.sleep()要智慧很多的。
下一次分享 顯式等待(二)expected_conditions類
交流技術 歡迎+QQ 153132336 zy