前言
①在進行WEB自動化工作時,一般要等待某一頁面元素加載完成后,才能對該元素執行操作,否則自動化腳本會拋出找不到元素的錯誤,這樣就要求我們在UI自動化測試的有些場景上加上等待時間。
②等待方式的設置是保證自動化腳本穩定有效運行的一個非常重要的手段。
強制等待 sleep()
①強制等待,設置固定休眠時間。
②python 的 time 包提供了休眠方法 sleep() ; 導入 time 包后就可以使用 sleep() ,進行腳本的執行過程進行休眠。
代碼如下:
# coding = utf-8 from time import sleep from selenium import webdriver
# 驅動文件路徑 driverfile_path = r'D:\coship\Test_Framework\drivers\chromedriver.exe' # 啟動瀏覽器 driver = webdriver.Chrome(executable_path=driverfile_path) # 打開百度首頁 driver.get(r'https://www.baidu.com/') # 等待3秒 sleep(3) driver.find_element_by_css_selector("#kw").send_keys("selenium") # 退出 driver.quit()
隱式等待driver.implicitly_wait(time)
①相當於設置全局的等待,在定位元素時,對所有元素設置超時時間。
②設置一個等待時間,如果在這個等待時間內,網頁加載完成,則執行下一步;否則一直等待時間截止,然后再執行下一步。這樣也就會有個弊端,程序會一直等待整個頁面加載完成,直到超時,但有時候我需要的那個元素早就加載完成了,只是頁面上有個別其他元素加載特別慢,我仍要等待頁面全部加載完成才能執行下一步。
③隱式等待使得 WebDriver 在查找一個 Element 或者 Elements 數組時,每隔一段特定的時間就會輪詢一次DOM,如果 Element 或 Elements 數組沒有馬上被發現的話。默認設置是0。一旦設置,這個隱式等待會在WebDriver對象實例的整個生命周期起作用。
# coding = utf-8 from selenium import webdriver
# 驅動文件路徑 driverfile_path = r'D:\coship\Test_Framework\drivers\chromedriver.exe' # 啟動瀏覽器 driver = webdriver.Chrome(executable_path=driverfile_path) # 打開百度首頁 driver.get(r'https://www.baidu.com/') driver.find_element_by_css_selector("#kw").send_keys("selenium") driver.find_element_by_css_selector("#su").click() # 隱式等待30秒 driver.implicitly_wait(30) result = driver.find_elements_by_css_selector("h3.t>a") for i in result: print(i.text) # 退出 driver.quit()
顯示等待
①上面我們說了隱式等待的一個弊端,如果我想等我要的元素一加載出來就執行下一步,該怎么辦?這里就要用到顯示等待。
②顯式等待是你定義的一段代碼,用於等待某個條件發生然后再繼續執行后續代碼。
③ 在設置時間內,默認每隔一段時間檢測一次當前頁面元素是否存在,如果超過設置時間檢測不到則拋出異常。默認檢測頻率為0.5s,默認拋出異常為: NoSuchElementException 。
④ WebDriverWait 的幫助文檔:
>>> help(WebDriverWait) Help on class WebDriverWait in module selenium.webdriver.support.wait: class WebDriverWait(builtins.object) | Methods defined here: | | __init__(self, driver, timeout, poll_frequency=0.5, 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 | | element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_i d("someId")) | | is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleExcepti on)).\ | | until_not(lambda x: x.find_element_by_id("someId").is_displ ayed())
創建一個 WebDriverWait 類的實例對象: WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
主要有4個參數:
driver :瀏覽器驅動
timeout :等待時間
poll_frequency :檢測的間隔時間,默認0.5s
ignored_exceptions :超時后的異常信息,默認拋出NoSuchElementException
⑤顯示等待要用到 WebDriverWait 類:
from selenium.webdriver.support.wait import WebDriverWait
代碼示例1:
#encoding=utf-8 from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait #獲取單個頁面元素對象,顯示等待 #locateType查找的方法類型 #locatorExpression查找的表達式 def getElement(driver,locateType,locatorExpression): try: element=WebDriverWait(driver,5).until(lambda x: x.find_element(by=locateType, value=locatorExpression)) except Exception, e: raise e
代碼示例2:
# coding = utf-8 from selenium import webdriver from selenium.webdriver.support.wait import WebDriverWait
# 驅動文件路徑 driverfile_path = r'D:\coship\Test_Framework\drivers\chromedriver.exe' # 啟動瀏覽器 driver = webdriver.Chrome(executable_path=driverfile_path) # 打開百度首頁 driver.get(r'https://www.baidu.com/') driver.find_element_by_css_selector("#kw").send_keys("selenium") driver.find_element_by_css_selector("#su").click() # 超時時間為30秒,每0.2秒檢查1次,直到class="tt"的元素出現 text = WebDriverWait(driver, 30, 0.2).until(lambda x:x.find_element_by_css_selector(".tt")).text print(text) # 退出 driver.quit()
代碼示例3:
from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By driver = webdriver.Firefox() driver.get('http://www.baidu.com') element = WebDriverWait(driver, 5, 0.5).until(EC.presence_of_element_located((By.ID, "kw"))) element.send_keys('selenium')
在本例中,通過as關鍵字將 expected_conditions 重命名為EC,並調用 presence_of_element_located() 方法判斷元素是否存在。
expected_conditions 類提供的預期條件判斷的方法
方法 | 說明 |
---|---|
title_is | 判斷當前頁面的 title 是否完全等於(==)預期字符串,返回布爾值 |
title_contains | 判斷當前頁面的 title 是否包含預期字符串,返回布爾值 |
presence_of_element_located | 判斷某個元素是否被加到了 dom 樹里,並不代表該元素一定可見 |
visibility_of_element_located | 判斷某個元素是否可見. 可見代表元素非隱藏,並且元素的寬和高都不等於 0 |
visibility_of | 跟上面的方法做一樣的事情,只是上面的方法要傳入 locator,這個方法直接傳定位到的 element 就好了 |
presence_of_all_elements_located | 判斷是否至少有 1 個元素存在於 dom 樹中。舉個例子,如果頁面上有 n 個元素的 class 都是'column-md-3',那么只要有 1 個元素存在,這個方法就返回 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進去,如果可以的話,返回 True 並且 switch 進去,否則返回 False |
invisibility_of_element_located | 判斷某個元素中是否不存在於dom樹或不可見 |
element_to_be_clickable | 判斷某個元素中是否可見並且是 enable 的,這樣的話才叫 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 |
Expected Conditions 的使用場景有2種:
- 直接在斷言中使用
- 與 WebDriverWait() 配合使用,動態等待頁面上元素出現或者消失
實例:
#encoding:utf-8 # example of how to use https://github.com/SeleniumHQ/selenium/blob/master/py/selenium/webdriver/support/expected_conditions.py from selenium import webdriver from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.common.by import By import unittest # dr = webdriver.PhantomJS('phantomjs') dr = webdriver.Firefox() # dr = webdriver.Chrome() url = 'http://www.baidu.com' search_text_field_id = 'kw' dr.get(url) class ECExample(unittest.TestCase): def test_title_is(self): ''' 判斷title是否符合預期 ''' title_is_baidu = EC.title_is(u'百度一下,你就知道') self.assertTrue(title_is_baidu(dr)) def test_titile_contains(self): ''' 判斷title是否包含預期字符 ''' title_should_contains_baidu = EC.title_contains(u'百度') self.assertTrue(title_should_contains_baidu(dr)) def test_presence_of_element_located(self): ''' 判斷element是否出現在dom樹 ''' locator = (By.ID, search_text_field_id) search_text_field_should_present = EC.visibility_of_element_located(locator) ''' 動態等待10s,如果10s內element加載完成則繼續執行下面的代碼,否則拋出異常 ''' WebDriverWait(dr, 10).until(EC.presence_of_element_located(locator)) WebDriverWait(dr, 10).until(EC.visibility_of_element_located(locator)) self.assertTrue(search_text_field_should_present(dr)) def test_visibility_of(self): search_text_field = dr.find_element_by_id(search_text_field_id) search_text_field_should_visible = EC.visibility_of(search_text_field) self.assertTrue(search_text_field_should_visible('yes')) def test_text_to_be_present_in_element(self): text_should_present = EC.text_to_be_present_in_element((By.NAME, 'tj_trhao123'), 'hao123') self.assertTrue(text_should_present(dr)) @classmethod def tearDownClass(kls): print 'after all test' dr.quit() print 'quit dr' if __name__ == '__main__': unittest.main()
以title_is為例分析:
class title_is(object): """An expectation for checking the title of a page. title is the expected title, which must be an exact match returns True if the title matches, false otherwise.""" def __init__(self, title): self.title = title def __call__(self, driver): return self.title == driver.title
可以看到 title_is 實際上是1個類,其 __call__ 方法被定義成是返回1個bool值。因此,一般的用法就是:
# 實例化 the_instance = title_is('expected') # 直接在實例上調用__call__ the_instance(dr) #return True or False
詳解webDriverWait()
WebDriverWait(self,driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None).until(self, method, message=)
或者:
WebDriverWait(self, driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None).until_not(self,method, message=)
① self : 函數本身,在實際使用的時候不需要輸入。
② driver :webdriver的驅動程序,如(IE、FireFox、chrome、safari等)。
③ timeout :超時時間,默認以秒為單位 poll_frequency ,休眠時間(步長)的間隔,默認為0.5秒,即檢測元素是否存在的頻率。
④ ignored_exceptions :超時后的異常信息,默認情況下拋 NoSuchElementException 異常信息,可以定義忽略的異常信息。
⑤ WebDriverWait 一般由 until 或 until_not 配合使用。
⑥ until(method, message=") :調用該方法提供的驅動程序做為一個參數,直到返回值不為 False 。
⑦ until_not(method, message=") :調用該方法提供的驅動程序做為一個參數,直到返回值為 False 。
實際應用
在自動化測試中,很多時候都會有等待頁面某個元素出現后能進行下一步操作,或者列表中顯示加載,直到加載完成后才進行下一步操作,但時間都不確定,如下圖所示:
代碼如下:
from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.by import By import selenium.webdriver.support.expected_conditions as EC import selenium.webdriver.support.ui as ui # 一直等待某元素可見,默認超時10秒 def is_visible(locator, timeout=10): try: ui.WebDriverWait(driver, timeout).until(EC.visibility_of_element_located((By.XPATH, locator))) return True except TimeoutException: return False # 一直等待某個元素消失,默認超時10秒 def is_not_visible(locator, timeout=10): try: ui.WebDriverWait(driver, timeout).until_not(EC.visibility_of_element_located((By.XPATH, locator))) return True except TimeoutException: return False # 調用 is_not_visible('//input[@input="search-error"]')
參考博客:https://www.cnblogs.com/nbkhic/p/4885041.html