需求:使用python selenium來自動測試一個網站注冊的流程。
假設這個網站的注冊流程分為三步,需要提供比較多的信息:

在這個流程里面,需要用戶填入信息、在下拉菜單中選擇、選擇單選的radio button、多選框等等比較復雜的頁面元素操作。
在開始做的時候,我會按照一個用戶真正的填寫習慣,參照頁面,一步步的定義每個步驟應該進行怎樣的操作,我需要查看每一個頁面元素的屬性,決定選擇一個合理的選項,然后再用代碼自動化這樣的操作。但是反思一下,其實這樣的實現方法並不符合一個計算機自動測試的習慣,也浪費了許多時間在手動的尋找頁面元素的相關屬性和合理操作值上。
所謂的自動化,就是要機器在最大程度上的去代替人進行某些操作。而只有在程序自己沒有辦法判斷如何操作的時候,我們才為這類操作定義更詳細的規定。例如:從計算機的角度,並不需要關心radio button要選擇的是male或是female,也不關心下拉菜單中我們要選擇的具體的值是什么;它只需要確保radio button和下拉菜單中可以順利的選擇到一個元素。因此,在這個注冊流程中,我可以簡單的定義找到頁面上所有的radio button,然后挨個把它們都點擊一遍,這樣既能保證每個radio button都被點擊事件測試過,也能保證在注冊流程中必定有一個選項被選中了。同樣的,我可以定義對每個下拉菜單都選擇第一個字值。這樣的general的方法,可以把我從對每個元素都要找到它的屬性然后對其指定詳細的操作的辛苦中一次性的解放出來:
def click_radio_btn(driver): radioBtns = driver.find_elements_by_xpath("//input[@type='radio']") for radioBtn in radioBtns: if radioBtn.is_displayed(): radioBtn.click()
這里我多進行了一次radioBtn.is_displayed()的判斷,原因是在我的流程中有的radio button是在選擇了某些特定選項之后才會顯示在頁面上的,因此對於沒有顯示的元素就不必進行點擊操作,否則會拋出異常:
selenium.common.exceptions.ElementNotVisibleException: Message: u'element not visible
而對於需要填入具體信息的input field來說,我們就必須要給出具體每個輸入框的輸入值來告訴程序如何處理這些元素了。
在這個這個注冊流程中,address的下拉菜單中市的選項是基於省份的選值的。這里有一個ajax的異步調用,當用戶選擇了一個省份之后才會對市下拉單中的值進行加載。於是問題出現了:由於網絡的原因,加載市的值的速度是不一定的,有時也許在執行對市的下拉菜單進行選值的時候其中的值其實還沒有加載完成。這時,雖然我們選擇的是第一個選項,還是會拋出異常:
selenium.common.exceptions.NoSuchElementException: Message: 'Could not locate element with index 1'
這種情況的解決辦法是:使用selenium.webdriver.support.ui.WebDriverWait提供的until來使webdriver等待到指定的條件滿足或是規定的timeout time到期:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
driver.get("http://www.zhuce.com") city = WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.NAME,"city"))) Select(city).select_by_index(1)
這樣,webdriver將會等待name為“city”的元素enable了之后才算找到該元素,並繼續進行接下來的點擊操作。如果在10秒內該元素都沒有加載成功的話,才拋出異常:
raise TimeoutException(message) selenium.common.exceptions.TimeoutException: Message: ''
python selenium中提供了多種元素等待的條件:
title_is title_contains presence_of_element_located visibility_of_element_located visibility_of presence_of_all_elements_located text_to_be_present_in_element text_to_be_present_in_element_value frame_to_be_available_and_switch_to_it invisibility_of_element_located element_to_be_clickable #it is Displayed and Enabled. staleness_of element_to_be_selected element_located_to_be_selected element_selection_state_to_be element_located_selection_state_to_be alert_is_present
