Selenium Web自動化測試——基於unittest框架的PO設計模式

  引言

  前面一直在講接口自動化測試框架與案例分享,不多講Selenium這個Web自動化測試神器。它主要用來作UI自動化測試,你們都知道UI自動化測試成本至關高,通常的Web自動化測試我是一直不建議作的。
python

  雖然不推薦,可是這裏有一個設計思想是不錯的——PO設計模式。web

  PO設計模式

  PO設計模式,英文名稱:Page Object Model。PO設計模式是Selenium自動化測試中最佳的設計方式之一。相比傳統設計中:頁面定位元素→輸入數據→操做元素→斷言結果,會有如下問題:設計模式

  一、易用性差:雜亂無章的定位元素方法,例如:find_element;瀏覽器

  二、擴展性很差:用例孤立,沒法擴展;框架

  三、複用性差:無公共方法,很難服用;學習

  四、可維護性差:一旦元素變化或測試步驟變化,須要維護大量代碼和用例;測試

  針對上面一些弊端,作了一些優化:優化

  POM設計模式,將頁面定位和業務操做分開,將元素定位和測試方法分離,從而提升代碼的維護性。而傳統的POM是元素定位和測試方法放在一塊兒,以下圖:ui

  

 

  這樣作的優點:url

  一、頁面元素定位和業務操做方法分離,使得代碼更加清晰,減小冗餘代碼;

  二、測試方法單獨抽離,這樣提升用例的可讀性;

  三、針對ui變化頻繁的項目和測試步驟的變化,提升了測試用例的維護性;

  一條測試用例可能須要多個步驟操做元素,將每個步驟單獨封裝成一個方法,在執行測試用例時調用封裝好的方法進行操做。PO模式能夠把一個頁面分爲三個層級,對象庫層、操做層、業務層。

  對象庫層:封裝定位元素的方法。
  操做層:封裝對元素的操做。
  業務層:將一個或多個操做組合起來完成一個業務功能。

  PO設計模式核心組件

  畫一個操做以下:

  

 

   首先抽象封裝一個BasePage類,這個基類擁有Webdriver實例的屬性,將頁面分紅一個個Page,每個Page繼承基類BasePage,能夠經過driver來管理每個Page中的元素,

  在Page中將定位元素的操做封裝成一個一個方法。TestCase繼承unittest裏面的TestCase類,而且依賴Page類,進行測試步驟的執行工做。

  這樣以來,頁面元素一旦變化,只須要維護每個Page中的方法,測試流程發生變化,只須要維護TestCase便可。

  核心組件:

  BasePage.py模塊:

class BasePage(object):
    def __init__(self,driver):
        self.driver = driver

    pass

  Page頁面模塊:

from SeleniumProject.PO.BasePage import BasePage
class LoginBase(BasePage):
    # 定位元素,括號中是經過find_element來獲取元素的屬性
    uname = ()
    pwd = ()

    def set_uname(self,uname):
        name =self.driver.find_element(*LoginBase.uname)
        name.send_keys("用戶名")
    def set_pwd(self,pwd):
        password = self.driver.find_element(*LoginBase.pwd)
        password.send_keys("密碼")

    pass

  TestCase用例模塊:

from unittest import TestCase
import unittest
from selenium import webdriver
class Test_Login(TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.get("https://cn.bing.com/")

    # 測試步驟
    def test_Login(self):
        self.driver.get(self.base_url)
        pass

    def tearDown(self):
        self.driver.quit()

if __name__ == "__main__":
    unittest.main()

  

  PO模式簡單實例

  如今根據PO設計模式思想,簡單實現一個需求:

  打開瀏覽器,輸入url:https://www.baidu.com,在百度搜索文本框內輸入關鍵字:selenium,而後單擊:百度一下,進行搜索。

  根據需求,設計步驟以下:

  BasePage:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
# @Time    : 2020/11/22 0022 16:07
# @Author  : liudinglong
# @File    : basepage.py
# @Description: 
# @Question: 
'''
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC


class BasePage(object):
    def __init__(self,driver,url):
        """

        @param driver:
        @param base_url:
        """
        self.dr = driver
        self.base_url =  url

    # 定義私有方法,類對象和子類能夠訪問
    def _open(self,url):
        self.dr.get(url)
        self.dr.maximize_window()

    # 定義open方法,調用_open方法
    def open(self):
        self._open(self.base_url)

    def find_emelemt(self,*loc):
        try:
            WebDriverWait(self.dr,10).until(EC.visibility_of_all_elements_located(loc))
            return self.dr.find_element(*loc)
        except:
            print("頁面中沒有%s元素"%(self.loc))

    # 定義script()方法,用於執行JS腳本,比方上上傳文件啥的
    def script(self, src):
        self.dr.excute_script(src)

        # 定義頁面跳轉方法,比方說有的頁面有frame嵌套

    def switch_frame(self, loc):
        return self.dr.switch_to_frame(loc)

        # 從新定義send_keys()方法,爲了保證搜索按鈕是否存在,還有有的輸入框中默認有值,要清空

    def send_keys(self, loc, value, clear_first=True, click_first=True):
        try:
            # getattr方法至關於實現了self.loc
            loc = getattr(self, "_%s" % loc)
            # 是否存在搜索按鈕
            if click_first:
                self.find_emelemt(*loc).click()
            # 清空搜索框中的值,並輸入須要搜索的值
            if clear_first:
                self.find_emelemt(*loc).clear()
                self.find_emelemt(*loc).send_keys(value)

        except:
            print("頁面上未找到%s元素" % (self.loc))

  SearchPage:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
# @Time    : 2020/11/22 0022 18:38
# @Author  : liudinglong
# @File    : SearchPage.py
# @Description: 
# @Question: 
'''

from selenium.webdriver.common.by import By
from Common.basepage import  BasePage

class SearchPage(BasePage):
    # 定位元素
    search_loc = (By.ID,"kw") #搜索框
    btn_loc = (By.ID,"su")    #搜索按鈕

    # 重寫父類的open()方法
    def open(self):
        self._open(self.base_url)

    def search_content(self,content):
        # 調用父類的find_emelemt,而後將本類的參數傳入
        content1 =  self.find_emelemt(*self.search_loc)
        content1.send_keys(content)

    def btn_click(self):
        btn1 = self.find_emelemt(*self.btn_loc)
        btn1.click()

  TestCase:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
# @Time    : 2020/11/22 0022 18:40
# @Author  : liudinglong
# @File    : test_001.py
# @Description: 
# @Question: 
'''

from unittest import TestCase
import unittest
from selenium import webdriver
from time import sleep
from Page.searchpage import SearchPage
class CaseRun(TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.url = "https://www.baidu.com"
        sleep(3)
        self.content = "selenium"
    # 測試步驟
    def test_search(self):
        bing_page = SearchPage(self.driver,self.url)
        bing_page.open()
        bing_page.search_content(self.content)
        try:
            bing_page.btn_click()
            sleep(3)
            print("查詢成功")
        except Exception as Error:
            print(Error)

    def tearDown(self):
        self.driver.quit()

if __name__ == "__main__":
    unittest.main()

  三個核心組件完成,項目結構以下:

  

 

   運行測試,生成報告以下:

C:\Users\Administrator\Desktop\Demo_PO
C:\Users\Administrator\Desktop\Demo_PO\Report
.
Time Elapsed: 0:00:13.370322

Process finished with exit code 0

 

  總結

  這個Demo很簡單,主要意圖是幫助理解PO設計模式的思想,若是須要代碼,能夠加入QQ羣:696400122 ,咱們這裏主要是進行自動化測試和測試開發學習與溝通交流,若是其餘意圖請繞行~

相關文章
相關標籤/搜索