1. 程式人生 > >Python用Selenium做自動化測試(三):Page Object專題

Python用Selenium做自動化測試(三):Page Object專題

Page Object專題

頁面物件模型的設計優勢:

  • 創造可以被多個測試用例共享的可重用程式碼。
  • 減少大量重複的程式碼。
  • 如果使用者介面發生改變,則修改只用在一處進行。

Page Object Model (POM) & Page Factory in Selenium: Complete Tutorial

圖片來源:

目的:測試程式碼與被測頁面物件程式碼分離,後期如果有頁面元素髮生了更改,只需要修改相應頁面物件的程式碼(即對應Class檔案),而不需要修改測試的程式碼。

儘量使用XPath來尋找頁面元素。

    from selenium import webdriver
  2 from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
  3
import time 4 5 binary=FirefoxBinary('/usr/local/firefox/firefox') 6 driver=webdriver.Firefox(firefox_binary=binary) 7 print('Before login================') 8 title=driver.title 9 print(title) 10 now_url=driver.current_url 11 print(now_url) 12 13 driver.implicitly_wait(10) 14 driver.get(
"https://mail.qq.com/") 15 driver.switch_to_frame("login_frame") 16 driver.find_element_by_id("u").clear() 17 driver.find_element_by_id("u").send_keys("*") 18 driver.find_element_by_xpath("//*[@id='p']").clear() 19 driver.find_element_by_xpath("//*[@id='p']").send_keys("*") 20 driver.find_element_by_xpath(
"//*[@id='login_button']").click() 21 print('After login===================') 22 title=driver.title 23 print(title) 24 now_url=driver.current_url 25 print(now_url) 26 user=driver.find_element_by_xpath("//*[@id='useralias']").text 27 print(user) 28 driver.quit()

參照

的寫法寫了一下,執行時長11s.

test_qq.py

  1 import unittest
  2 from selenium import webdriver
  3 from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
  4 import page
  5 import time
  6 
  7 
  8 class LoginQQ(unittest.TestCase):
  9     def setUp(self):
 10         binary=FirefoxBinary('/usr/local/firefox/firefox')
 11         self.driver = webdriver.Firefox(firefox_binary=binary)
 12         self.driver.implicitly_wait(10)
 13         self.driver.get("https://mail.qq.com/")
    		#跳轉表單,這裡沒有分割出來,需要改進
 14         self.driver.switch_to_frame("login_frame")
 15     def test_login(self):
 16         main_page = page.MainPage(self.driver)
            #測試資料
 17         main_page.input_username="*"
 18         main_page.input_password="*"
 19         main_page.click_button()
 20     def tearDown(self):
 21         self.driver.close()
 22 if __name__ == "__main__":        
 23     unittest.main()

  1 from element import BasePageElement
  2 from locators import MainPageLocators
  6 class UsernameElement(BasePageElement):
  7     #元素定位
		locator='u'
  8 class PasswordElement(BasePageElement):    
  9     locator='p'
 10 class BasePage(object):
 11     def __init__(self,driver):
 12         self.driver=driver
 13 class MainPage(BasePage):
 14     input_username=UsernameElement()
 15     input_password=PasswordElement()
 16     def click_button(self):
 17         element=self.driver.find_element(*MainPageLocators.login_loc)
 18         element.click()

  1#元素操作
  2 class BasePageElement(object):
  3     def __set__(self,obj,value):
  4         driver=obj.driver
  5         driver.find_element_by_id(self.locator).clear()
  6         driver.find_element_by_id(self.locator).send_keys(value)
  7        
  8     def __get__(self,obj,owner):
  9         driver=obj.driver
 10         element=driver.find_element_by_id(self.locator)
 11         return element.get_attribute("value")

  1 from selenium.webdriver.common.by import By
  2 class MainPageLocators(object):
  3     login_loc = (By.XPATH,"//*[@id='login_button']")

又經過蟲師的書以及網上一些參考,進一步優化PageObject如下。

主要思想:將一個page物件封裝成一個HTML頁面,然後通過提供的應用程式特定的API來操作頁面元素。一個API是關於應用的,一個API是關於HTML的。因此,page物件提供一個易於程式設計的介面並隱藏視窗中底層的部件。

  • 訪問一個文字框通過一個訪問方法(accessor method)來實現字串的獲取和返回
  • 複選框使用布林值
  • 按鈕被表示為行為導向的方法名。

即page物件應當將GUI控制元件上所有查詢和操作資料的行為封裝為方法

test_qq.py

#coding=utf-8                                                                              
  2 import unittest
  3 
  4 from po_model import LoginPage
  5 from selenium import webdriver                                                             
  6 from selenium.webdriver.firefox.firefox_binary import FirefoxBinary                        
  7 from po_model import test_user_login                                                       
  8 from time import sleep                                                                     
  9 class test_qq(unittest.TestCase):                                                          
 10     def setUp(self):                                                                       
 11         binary=FirefoxBinary('/usr/local/firefox/firefox')                                 
 12         self.driver=webdriver.Firefox(firefox_binary=binary)                               
 13         self.driver.implicitly_wait(30)                                                    
 14     def test_login(self):
 15         username='*'                                                        
 16         password='*'                                                         
 17         test_user_login(self.driver,username,password)
 18         sleep(3)
 19         text = self.driver.find_element_by_xpath("//*[@id='useraddr']").text               
 20         assert(text == '[email protected]',"使用者名稱稱不匹配,登入失敗")                 
 21     def tearDown(self):                                                                    
 22         self.driver.quit()
 23 if __name__ == "__main__":                                                                 
 24     unittest.main()

po_model.py

#coding=utf-8
from selenium import webdriver
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
from selenium.webdriver.common.by import By
from time import sleep

class Page(object):
    '''
    基礎類,用於頁面物件類的繼承
    '''
    login_url="https://mail.qq.com"
    def __init__(self,selenium_driver,base_url=login_url):
        self.base_url=base_url
        self.driver=selenium_driver
        self.timeout=30
    def on_page(self):
        return self.driver.current_url == (self.base_url+self.url) 
    def _open(self,url):
        url=self.base_url+url
        self.driver.get(url)
    def open(self):
        self._open(self.url)
    def switch(self):
        return self.driver.switch_to_frame(self.framename)
    def find_element(self,*loc):
        return self.driver.find_element(*loc)
class LoginPage(Page):
    '''
    qq郵箱登入頁面模型
    '''
    url='/'
    #定位器
    username_loc=(By.ID,"u")
    password_loc=(By.ID,"p")
    login_loc = (By.XPATH,"//*[@id='login_button']")
    #Action
    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).clear()
        self.find_element(*self.password_loc).send_keys(password)
    def submit(self):    
        self.find_element(*self.login_loc).click()

def test_user_login(driver,username,password):
    '''
    測試獲取的使用者名稱/密碼是否可以登入

    '''

    login_page=LoginPage(driver)
    login_page.open()
    driver.switch_to_frame("login_frame")
    login_page.type_username(username)
    login_page.type_password(password)
    login_page.submit()