Selenium的PO模式(Page Object Model)|(Selenium Webdriver For Python)


        研究Selenium + python 自動化測試有近兩個月了,不能說非常熟練,起碼對selenium自動化的執行有了深入的認識。
從最初無結構的代碼,到類的使用,方法封裝,從原始函數調用,到重定義函數。從變量驅動,到數據驅動,再到關鍵字驅動,一步一步的默默走向自動化框架的構建。 雖然還有沒有投入使用,只是寫幾個demo,就慢慢的發現了 selenium自動用例腳本,相似功能地方,代碼基本都是一樣的,界面元素換個查找方式,把原來的使用 xpath方式,改為使用 id 查找,需要對每個用例腳本都要改,雖然幾個用例看不出什么工作量,但是重復findElement的代碼,已經讓我們感到了代碼的笨重。如果某些定位發生了改變,我們就得貫穿整個測試代碼進行調整元素定位,這樣就會導致我們的腳本在后期,難以維護。
        因此通過Page Object Model 我們可以創建更加健壯代碼,並減少或者消除重復的測試代碼,從而也能夠提高代碼的可讀性,減少編寫腳本的工作量。Page Object Model的實現,就是通過分離測試對象和測試腳本的抽象來實現的。
PO項目實戰演示Demo源碼:(源碼會隨着結構調整不斷更新,但是整體結構不會變動)
 Page Object Model 簡稱POM 
下面通過一個實例演示POM的實現
在此之前,先看一個段比較普通的測試用例代碼片段:
  1.  1 ....
     2 #測試用例 
     3 def test_login_mail(self):
     4  driver = self.driver 
     5  driver.get("http://mail.126.com")
     6  driver.find_element_by_id("idInput").clear()
     7  driver.find_element_by_id("idInput").send_keys("auto_tester")
     8  driver.find_element_by_id("pwdInput").clear()
     9  driver.find_element_by_id("pwdInput").send_keys("123456")
    10  driver.find_element_by_id("loginBtn").click()
    11 ....

     

這段腳本實現,是126郵箱登錄功能的一個測試用例,單純從這段代碼來看,並不能直觀知道他實現了什么業務,而且對於同一個元素,都出現重復的定位代碼,只一個簡單的登錄功能,一個用例只操作3個元素,就暴露出來了一些代碼冗余和可讀性的問題。那么如果有更多功能和更多用例,那么用例代碼更加厚重,可讀性也是大大降低,我們需要想辦法對此代碼進行優化,通過POM實現登錄功能。
 
首先,我們要分離測試對象(元素對象)和測試腳本(用例腳本),那么我們分別創建兩個腳本文件, LoginPage.py 用於定義頁面元素對象,每一個元素都封裝成組件(可以看做存放頁面元素對象的倉庫)  CaseLoginTest.py 測試用例腳本。我們的實現思想,一切元素和元素的操作組件化定義在Page頁面,用例腳本頁面,通過調用Page中的組件對象,進行拼湊成一個登錄腳本。
在寫這兩個腳本之前,我先對WebDriver中的一些方法進行重定義,以方便我們在寫PO的時候,更簡潔,快速。
BasePage.py:
  1.  1 #-*- coding: utf-8 -*-
     2 __author__ ='tsbc'
     3 from selenium.webdriver.support.wait importWebDriverWait
     4 from selenium import webdriver
     5 classAction(object):
     6 """
     7  BasePage封裝所有頁面都公用的方法,例如driver, url ,FindElement等
     8 """
     9 #初始化driver、url、等
    10 def __init__(self, selenium_driver, base_url, pagetitle):
    11  self.base_url = base_url
    12  self.pagetitle = pagetitle
    13  self.driver = selenium_driver
    14 
    15 #打開頁面,校驗頁面鏈接是否加載正確
    16 def _open(self, url, pagetitle):
    17 #使用get打開訪問鏈接地址
    18 self.driver.get(url)
    19  self.driver.maximize_window()
    20 #使用assert進行校驗,打開的鏈接地址是否與配置的地址一致。調用on_page()方法
    21 assert self.on_page(pagetitle), u"打開開頁面失敗 %s"% url
    22 
    23 #重寫元素定位方法
    24 def find_element(self,*loc):
    25 #return self.driver.find_element(*loc)
    26 try:
    27 WebDriverWait(self.driver,10).until(lambda driver: driver.find_element(*loc).is_displayed())
    28 return self.driver.find_element(*loc)
    29 except:
    30 print u"%s 頁面中未能找到 %s 元素"%(self, loc)
    31 
    32 #重寫switch_frame方法
    33 def switch_frame(self, loc):
    34 return self.driver.switch_to_frame(loc)
    35 #定義open方法,調用_open()進行打開鏈接
    36 
    37 def open(self):
    38  self._open(self.base_url, self.pagetitle)
    39 
    40 #使用current_url獲取當前窗口Url地址,進行與配置地址作比較,返回比較結果(True False)
    41 def on_page(self, pagetitle):
    42 return pagetitle in self.driver.title
    43 
    44 #定義script方法,用於執行js腳本,范圍執行結果
    45 def script(self, src):
    46  self.driver.execute_script(src)
    47 
    48 #重寫定義send_keys方法
    49 def send_keys(self, loc, vaule, clear_first=True, click_first=True):
    50 try:
    51  loc = getattr(self,"_%s"% loc)
    52 if click_first:
    53  self.find_element(*loc).click()
    54 if clear_first:
    55  self.find_element(*loc).clear()
    56  self.find_element(*loc).send_keys(vaule)
    57 exceptAttributeError:
    58 print u"%s 頁面中未能找到 %s 元素"%(self, loc)

    LoginPage.py:

  2.  1 #-*- coding: utf-8 -*-
     2 __author__ ='tsbc'
     3 
     4 from selenium.webdriver.common.by importBy
     5 importBasePage
     6 
     7 #繼承BasePage類
     8 classLoginPage(BasePage.Action):
     9 
    10 #定位器,通過元素屬性定位元素對象
    11 username_loc =(By.ID,"idInput")
    12  password_loc =(By.ID,"pwdInput")
    13  submit_loc =(By.ID,"loginBtn")
    14  span_loc =(By.CSS_SELECTOR,"div.error-tt>p")
    15  dynpw_loc =(By.ID,"lbDynPw")
    16  userid_loc =(By.ID,"spnUid")
    17 
    18 #Action
    19 def open(self):
    20 #調用page中的_open打開連接
    21 self._open(self.base_url, self.pagetitle)
    22 #調用send_keys對象,輸入用戶名
    23 def input_username(self, username):
    24  self.find_element(*self.username_loc).send_keys(username)
    25 #調用send_keys對象,輸入密碼
    26 def input_password(self, password):
    27  self.find_element(*self.password_loc).send_keys(password)
    28 #調用send_keys對象,點擊登錄
    29 def click_submit(self):
    30  self.find_element(*self.submit_loc).click()
    31 #用戶名或密碼不合理是Tip框內容展示
    32 def show_span(self):
    33 return self.find_element(*self.span_loc).text
    34 #切換登錄模式為動態密碼登錄(IE下有效)
    35 def swich_DynPw(self):
    36  self.find_element(*self.dynpw_loc).click()
    37 #登錄成功頁面中的用戶ID查找
    38 def show_userid(self):
    39 return self.find_element(*self.userid_loc).text
    40 
    41 CaseLoginTest.py:
    42 #-*- coding: utf-8 -*-
    43 __author__ ='tsbc'
    44 import sys
    45 reload(sys)
    46 sys.setdefaultencoding('utf-8')
    47 import unittest 
    48 from PO importLoginPage
    49 from selenium import webdriver
    50 
    51 classCaselogin126mail(unittest.TestCase):
    52 """
    53 登錄126郵箱的case
    54  """
    55 @classmethod
    56 def setUpClass(cls):
    57  cls.driver = webdriver.Chrome()
    58  cls.driver.implicitly_wait(30)
    59 
    60  cls.url ="http://mail.126.com"
    61  cls.username ="auto_tester"
    62  cls.password ="123456"
    63 
    64 #用例執行體
    65 def test_login_mail(self):
    66 #聲明LoginPage類對象
    67 login_page =LoginPage.LoginPage(self.driver, self.url, u"網易")
    68 
    69 #調用打開頁面組件
    70 login_page.open()
    71 #調用用戶名輸入組件
    72 login_page.input_username(self.username)
    73 #調用密碼輸入組件
    74 login_page.input_password(self.password)
    75 #調用點擊登錄按鈕組件
    76 login_page.click_submit()
    77 @classmethod
    78 def tearDownClass(cls):
    79  cls.driver.quit()
    80 
    81 if __name__ =="__main__":
    82  unittest.main()

     

通過使用POM進行重新構造代碼結構后,發現代碼測試用例代碼的可讀性提高很多,元素寫成組件的方式,不需要每次都寫findElement直接在腳本中調用組件就可以使用。在CaseLoginTest腳本用例執行體中,一旦我們輸入 login_page並敲入一個點時,LoginPage頁面中的元素對象組件都顯示出來。並且定義好的PageObject組件可以重復在其它的腳本中進行使用,減少了代碼的工作量,也方便對腳本進行后期的維護管理,當元素屬性發生變化時,我們只需要對一個PageObaject頁面中的對象組件定義進行更改即可。

<簡單對Page Object Model使用實例進行描述,希望能夠對Selenium自動化的POM理解有所幫助>






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM