能否構建健壯和可靠的測試是UI自動化測試能否成功的關鍵因素之一。但實際情況是當一個測試接着一個測試執行的時候,常會遇到各種不同的狀況。比如腳本去定位元素或去驗證程序的運行狀態時,有時會發現找不到元素,這可能是由於突然的資源受限或網絡延遲等引起響應速度太慢所導致,這時會返回測試失敗的結果。so我們需要在測試腳本中引入延時機制,來使腳本的運行速度與程序的響應速度相匹配。即使腳本和程序的響應能夠同步。WebDriver為我們提供了隱式等待和顯式等待兩種機制。下面一一說明下:
隱式等待
隱式等待為WebDriver中的完整一個測試用例或者一組測試的同步,提供了通用的方法。對於解決由於網絡延遲或利用Ajax動態加載所導致的程序響應時間不一致是非常有效的。
當設置了隱式等待時間后,WebDriver會在一定時間內持續檢測和搜尋DOM,以便於查找一個或多個不立即加載成功可用的元素。一般情況下,隱式等待的默認超時間設置為0。但一旦設置會作用於這個WebDriver實例的整個生命周期或者說一次完整測試的執行期間,並且WebDriver會使其對所有測試步驟中包含的整個頁面的元素查找時都有效。
WebDriver提供了implicity_wait()方法來配置超時時間。基於unittest寫的測試腳本,常在setUp()方法中加入隱式等待時間並設置為30秒。當測試執行時,WebDriver在找不到一個元素時,將會等待30秒。當達到30秒超時時間后,將拋出一個NoSuchElementException的異常。下面是一個用到隱式等待機制的簡單百度搜索測試腳本,代碼如下:
import unittest from selenium import webdriver class BaiduSearchTest(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome() self.driver.implicitly_wait(30) #set implicit wait time 30s self.driver.maximize_window() #open the baidu page self.driver.get('https://www.baidu.com') def test_search_python(self): #get the search textbox search_textbox = self.driver.find_element_by_id('kw') search_textbox.clear() #enter search keyword search_textbox.send_keys("python") #get the and seacrh button and click search_button = self.driver.find_element_by_id('su') search_button.click() #add assert tag = self.driver.find_element_by_link_text("PyPI").text self.assertEqual('PyPI',tag) def tearDown(self): #close the browser window self.driver.quit() if __name__ == '__main__': unittest.main(verbosity=2)
顯式等待
顯式等待是WebDriver中用於同步測試的另外一種等待機制。顯式等待比隱式等待具備更好的操控性。與隱式等待不同,顯示等待需要為腳本設置一些預置或者定制化的條件,等待條件滿足后再進行下一步測試。
顯式等待可以只作用於僅有同步需要的測試用例。WebDriver提供了WebDriverWait類和expected_conditions類來實現顯式等待。expected_condition類提供了一些預置條件來作為測試腳本進行下一步測試的判斷依據。下面是一個包含顯式等待的簡單測試腳本,代碼如下:
import unittest from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions class BaitduExplicitWaitTest(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome() self.driver.get('https://www.baidu.com') def test_login_link(self): WebDriverWait(self.driver, 10).until(lambda s: s.find_element_by_name("tj_login").get_attribute("class") == "lb") login_link = WebDriverWait(self.driver, 10).until(expected_conditions.element_to_be_clickable((By.LINK_TEXT, "登錄"))) login_link.click() def tearDown(self): self.driver.quit() if __name__ == '__main__': unittest.main(verbosity=2)
上面腳本先使用python的lambda表達式,並且基於WebDriverWait來實現自定義的預期條件判斷。設置顯式等待超時時間為10s,直到獲取到登錄元素並判定其class屬性為1b。同時使用element_to_be_clickable方法來判斷預期條件是否滿足。該條件為等待通過定位器查找的元素可見並可用,這里為登錄選項可以點擊,直到最大等待時間10s。一旦根據指定的定位器找到了元素,預期條件判定方法會把元素返回給測試腳本以提供給下一步的單擊操作。如果在設定的超時時間內,沒有通過定位器找到可見可點擊的元素,將出拋出TimeoutExpection異常。
下表是expected_conditions類支持的網頁瀏覽器自動化操作時常用到的一些通用等待條件。
expected_conditions類已經提供了多種內置的預期等待判定條件,我們在實際工作中的可以直接調用。但如果超出了expected_conditions的范圍,不用怕,WebDriverWait類也提供了強大的自定義預期等待判定功能。
注意:應盡量避免在測試中隱式等待與顯式等待混合使用來處理同步問題。