Page Object模式是使用Selenium的廣大同行最為公認的一種設計模式。在設計測試時,把元素和方法按照頁面抽象出來,分離成一定的對象,然后再進行組織。
Page Object模式,創建一個對象來對應頁面的一個應用。故我們可以為每個頁面定義一個類,並為每個頁面的屬性和操作構建模型。體現在對界面交互細節的封裝,測試在更上層使用頁面對象,在底層的屬性或者操作的更改不會中斷測試。減少代碼重復,提高測試代碼的可讀性和可維護性。
下面將以登錄qq郵箱簡單為例,通過Page Object設計模式來實現。代碼如下:
from selenium import webdriver from selenium.webdriver.common.by import By from time import sleep #創建基礎類 class BasePage(object): #初始化 def __init__(self, driver): self.base_url = 'https://mail.qq.com/' self.driver = driver self.timeout = 30 #定義打開登錄頁面方法 def _open(self): url = self.base_url self.driver.get(url) self.driver.switch_to.frame('login_frame') #切換到登錄窗口的iframe
#定義定義open方法,調用_open()進行打開 def open(self): self._open() #定位方法封裝 def find_element(self,*loc): return self.driver.find_element(*loc) #創建LoginPage類 class LoginPage(BasePage): username_loc = (By.ID, "u") password_loc = (By.ID, "p") login_loc = (By.ID, "login_button") #輸入用戶名 def type_username(self,username): self.find_element(*self.username_loc).clear() self.find_element(*self.username_loc).send_keys(username) #輸入密碼 def type_password(self,password): self.find_element(*self.password_loc).send_keys(password) #點擊登錄 def type_login(self): self.find_element(*self.login_loc).click() #創建test_user_login()函數 def test_user_login(driver, username, password): """測試用戶名/密碼是否可以登錄""" login_page = LoginPage(driver) login_page.open() login_page.type_username(username) login_page.type_password(password) login_page.type_login() #創建main()函數 def main(): driver = webdriver.Edge() username = '3494xxxxx' #qq號碼 password = 'kemixxxx' #qq密碼 test_user_login(driver, username, password) sleep(3) driver.quit() if __name__ == '__main__': main()
雖然該實現方法看上去復雜多了,但其中的設計好處是不同層關心不同的問題。頁面對象只關心元素的定位,測試用例只關心測試數據。
下面將對上面代碼加以說明,首先創建一個基礎BasePage類,在初始化方法__init__()中定義驅動(driver),基本的URL(base_url)和超時時間(timeout)等。定義open()方法用於打開URL,這里是由_open()方法來實現,而find_element()方法用於元素定位。
接下來的BasePage類中定義的方法都是頁面操作的基本方法。LoginPage類並繼承BasePage類,這也是Page Object設計模式中最重要的對象層。LoginPage類中主要對登錄頁面上元素進行封裝,使其成為具體的操作方法。如對用戶名、密碼框和登錄按鈕都封裝成方法。
然后定義test_user_login()函數將單個元素操作組成一個完整的動作,包含打開瀏覽器、輸入用戶名、密碼並點擊登錄按鈕等。使用時將driver、username、password作為函數的入參,這樣的函數具有很強的可重用性。
最后使用main()函數進行用戶操作行為,現在只關心用哪個瀏覽器、登錄的用戶名和密碼是什么,至少輸入框、按鈕是如何定位的,則不關心。即實現了不同層關心不同問題。如果有多個用戶名/密碼需要登錄,那么只用改寫main()方法的參數即可。