python+selenium自動化軟件測試(第7章):Page Object模式


什么是Page ObjectModel模式
Page Objects是selenium的一種測試設計模式,主要將每個頁面看作是一個class。class的內容主要包括屬性和方法,屬性不難理解,就是這個頁面中的元素對象,比如輸入用戶名的輸入框,輸入登陸密碼的輸入框,登陸按鈕,這個頁面的url等,而方法,主要是指這個頁面可以提供的具體功能。
為什么選擇POM?
我們先看一段簡單的代碼如下:

from selenium import webdriver
import time
 
driver = webdriver.Firefox()
driver.implicitly_wait(30)
 
# 啟動瀏覽器,訪問百度
driver.get("http://www.baidu.com")
 
# 定位百度搜索框,並輸入selenium
driver.find_element_by_id("kw").send_keys("selenium")
 
# 定位百度一下按鈕並單擊進行搜索
driver.find_element_by_id("su").click()
time.sleep(5)

driver.quit()

這是一個簡單的小腳本。腳本維護看起來很簡單。但隨着時間測試套件的增長。隨着你在代碼中添加越來越多的行,事情變得艱難。
腳本維護的主要問題是,如果10個不同的腳本使用相同的頁面元素,並且該元素中的任何更改,則需要更改所有10個腳本。這是耗時且容易出錯的。
更好的腳本維護方法是創建一個單獨的類文件,它可以找到Web元素,填充或驗證它們。該類可以在使用該元素的所有腳本中重用。將來,如果web元素有變化,我們需要在1個類文件中進行更改,而不是10個不同的腳本。
什么是POM?
頁面對象模型  是 為Web UI元素創建Object Repository的設計模式  。
在這個模型下,對於應用程序中的每個網頁,應該有相應的頁面類。
此Page類將會找到該Web頁面的WebElements,並且還包含對這些WebElements執行操作的頁面方法。
這些方法的名稱應該按照他們正在執行的任務給出,即如果一個加載程序正在等待支付網關出現,POM方法名稱可以是waitForPaymentScreenDisplay()。

下圖為非POM和POM對比圖:

在自動化測試中,引入了Page Object Model(POM):頁面對象模式來解決,POM能讓我們的測試代碼變得可讀性更好,高可維護性,高復用性。
POM的優勢
1.    POM提供了一種在UI層操作、業務流程與驗證分離的模式,這使得測試代碼變得更加清晰和高可讀性。

2.    對象庫與用例分離,使得我們更好的復用對象,甚至能與不同的工具進行深度結合應用。

3.    可復用的頁面方法代碼會變得更加優化。

4.    更加有效的命名方式使得我們更加清晰的知道方法所操作的UI元素。例如我們要回到首頁,方法名命名為: gotoHomePage(),通過方法名即可清晰的知道具體的功能實現。

案例說明:
以下是簡單普通的登錄測試用例:

def test_login_mail(self):
 driver = self.driver
 driver.get("http://www.xxx.xxx.com")
 driver.find_element_by_id("idInput").clear()
 driver.find_element_by_id("xxxxxxx").send_keys("xxxxx")
 driver.find_element_by_id("xxxxxxx").clear()
 driver.find_element_by_id("xxxxxxx").send_keys("xxxxxx")
 driver.find_element_by_id("loginBtn").click()

那我們如何進行一個改造升級呢?
改造案例思路:
第一, 我們要分離測試對象(元素對象)和測試腳本(用例腳本),那么我們分別創建兩個腳本文件,分別為: LoginPage.py 用於定義頁面元素對象,每一個元素都封裝成組件(可以看做存放頁面元素對象的倉庫)  CaseLoginTest.py 測試用例腳本。
第二, 設計實現思想,一切元素和元素的操作組件化定義在Page頁面,用例腳本頁面,通過調用Page中的組件對象,進行拼湊成一個登錄腳本。

BasePage.py:

#-*- coding: utf-8-*-
from selenium.webdriver.support.wait importWebDriverWait
from seleniumimport webdriver
classAction(object):
"""
 BasePage封裝所有頁面都公用的方法,例如driver, url ,FindElement等
"""
#初始化driver、url、等

def __init__(self,selenium_driver, base_url, pagetitle):
    self.base_url = base_url
    self.pagetitle = pagetitle
    self.driver = selenium_driver
    #打開頁面,校驗頁面鏈接是否加載正確

def _open(self,url, pagetitle):
    #使用get打開訪問鏈接地址
    self.driver.get(url)
    self.driver.maximize_window()

#使用assert進行校驗,打開的鏈接地址是否與配置的地址一致。調用on_page()方法
    assertself.on_page(pagetitle), u"打開開頁面失敗 %s"% url
 
#重寫元素定位方法
def find_element(self,*loc):
    #returnself.driver.find_element(*loc)
try:
WebDriverWait(self.driver,10).until(lambdadriver: driver.find_element(*loc).is_displayed())
return self.driver.find_element(*loc)

except:
print u"%s 頁面中未能找到 %s 元素"%(self, loc)
 
#重寫switch_frame方法
def switch_frame(self, loc):
return self.driver.switch_to_frame(loc)
#定義open方法,調用_open()進行打開鏈接
def open(self):
 self._open(self.base_url, self.pagetitle)
 
#使用current_url獲取當前窗口Url地址,進行與配置地址作比較,返回比較結果(True False)
def on_page(self,pagetitle):
return pagetitlein self.driver.title
 
#定義script方法,用於執行js腳本,范圍執行結果
def script(self,src):
 self.driver.execute_script(src)

#重寫定義send_keys方法
def send_keys(self, loc, vaule, clear_first=True, click_first=True):
try:
 loc = getattr(self,"_%s"% loc)
if click_first:
 self.find_element(*loc).click()
if clear_first:
 self.find_element(*loc).clear()
 self.find_element(*loc).send_keys(vaule)
exceptAttributeError:
print u"%s 頁面中未能找到 %s 元素"%(self, loc)

LoginPage.py:

#-*- coding: utf-8-*-
from selenium.webdriver.common.by importBy
import BasePage
#繼承BasePage類
class LoginPage(BasePage.Action):
#定位器,通過元素屬性定位元素對象
 username_loc=(By.ID,"idInput")
 password_loc =(By.ID,"pwdInput")
 submit_loc =(By.ID,"loginBtn")
 span_loc=(By.CSS_SELECTOR,"div.error-tt>p")
 dynpw_loc =(By.ID,"lbDynPw")
 userid_loc =(By.ID,"spnUid")

#Action
def open(self):
#調用page中的_open打開連接
self._open(self.base_url,self.pagetitle)
#調用send_keys對象,輸入用戶名
def input_username(self, username):
 self.find_element(*self.username_loc).send_keys(username)
#調用send_keys對象,輸入密碼
def input_password(self, password):
 self.find_element(*self.password_loc).send_keys(password)
#調用send_keys對象,點擊登錄

def click_submit(self):
 self.find_element(*self.submit_loc).click()
#用戶名或密碼不合理是Tip框內容展示
def show_span(self):
returnself.find_element(*self.span_loc).text
#切換登錄模式為動態密碼登錄(IE下有效)
def swich_DynPw(self):
 self.find_element(*self.dynpw_loc).click()
#登錄成功頁面中的用戶ID查找
def show_userid(self):
returnself.find_element(*self.userid_loc).text
Caselongintest.py

#-*- coding: utf-8-*-
import sys
reload(sys)
sys.setdef aultencoding('utf-8')
import unittest
from POimportLoginPage
from seleniumimport webdriver
classCaselogin126mail(unittest.TestCase):
"""
登錄case
 """
@classmethod
def setUpClass(cls):
 cls.driver = webdriver.Chrome()
 cls.driver.implicitly_wait(30)
 
 cls.url ="http://xxxx.xxx.com"
 cls.username ="xxxxx"
 cls.password ="xxxxx"
 
#用例執行體
def test_login_mail(self):
#聲明LoginPage類對象
login_page=LoginPage.LoginPage(self.driver, self.url, u”xxxxx”)
 
#調用打開頁面組件
login_page.open()
#調用用戶名輸入組件
login_page.input_username(self.username)
#調用密碼輸入組件
login_page.input_password(self.password)
#調用點擊登錄按鈕組件
login_page.click_submit()
@classmethod
def tearDownClass(cls):
 cls.driver.quit()
 
if __name__=="__main__":
 unittest.main()

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

1.    POM是selenium webdriver自動化測試實踐對象庫設計模式
2.    POM使得測試腳本更易於維護
3.    POM通過對象庫方式進一步優化了元素、用例、數據的維護組織




免責聲明!

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



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