天天看點

自動化之PO模式(二)

1.PO基本介紹

測試PO模式(Page Object Model)

  測試頁面和測試腳本分離,即頁面封裝成類,供測試腳本進行調用。

優點

    1.提高測試用例的可讀性;

    2.減少了代碼的重複;

    3.提高測試用例的可維護性,特别是針對UI頻繁變動的項目;

缺點

    結構複雜: 基于流程做了子產品化的拆分。

自動化之PO模式(二)

2.Appium方法二次封裝

為什麼二次封裝方法?

    減少過多使用類似方法,更友善管理定位元素,盡量将函數方法簡潔化、統一化。

系統已提供定位方法

  driver.find_element_by_id()

  driver.find_element_by_class_name()

  driver.find_element_by_xpath()

  driver.find_elements_by_id()

  driver.find_elements_by_class_name()

  driver.find_elements_by_xpath()

  實際以上定位方法封裝以下方法:

      find_element(by=By.XX, value=None)

      find_elements(by=By.XX, value=None)

      # by:定位類型(By.ID,By.CLASS_NAME,By.XPATH)

      # value:定位元素的屬性值

封裝思路

為什麼做?

  使用統一的方法來完成元素的定位.

怎麼去做?

  借用:

      find_element(by=By.XX, value=None)

      find_elements(by=By.XX, value=None)

封裝實作(一)

  # 點選元素

  def click_element(self, location,location_vlaue):

      # location: 定位類型

      # location_vlaue: 定位元素屬性值

      self.find_element(location,location_vlaue).click()

  # 輸入内容

  def input_element(self, location,location_vlaue,text):

      # text: 需要輸入的值

      self.find_element(location,location_vlaue).send_keys(text)

  發現問題:

      沒有簡化參數的傳遞,僅僅将點選和輸入做了封裝.

封裝實作(二)

  # 點選元素

  def click_element(self, location):

      # location: 定位類型&定位屬性值,

      ⚠️ location類型為元祖 格式(By.ID,value),(By.CLASS_NAME,value),(By.XPATH,value)

      self.find_element(*location).click()

      # *location将元祖類型的值進行了一次解包操作,來滿足find_element的參數傳遞要求

  # 輸入内容

  def input_element(self, location,text):

      # text: 需要輸入的值

      self.fm = self.find_element(*location)

      self.fm.clear() # 需要先清空輸入框,防止有預設内容

      self.fm.send_keys(text)

自動化之PO模式(二)

Demo示例

  業務場景:

      1.進入設定

      2.點選搜尋按鈕

      3.輸入123

      4.點選搜尋框傳回按鈕

  封裝代碼:Base.py

      from selenium.webdriver.support.wait import WebDriverWait

      class Base(object):

          def __init__(self,driver):

              self.driver = driver

          def find_element(self,loc,timeout=10):

              # 封裝稱為智能等待方法

              # loc:類型為元祖,格式(By.ID,value),(By.CLASS_NAME,value),(By.XPATH,value)

              # timeout:搜尋逾時時間

              return WebDriverWait(self.driver, timeout).until(lambda x: x.find_element(*loc))

          def click_element(self,loc):

              # 封裝點選操作

              self.find_element(loc).click()

          def input_text(self,loc,text):

              # 封裝輸入操作

              self.fm = self.find_element(loc)

              self.fm.clear() # 需要先清空輸入框,防止有預設内容

              self.fm.send_keys(text)

  測試代碼: test.py

      from appium import webdriver

      from selenium.webdriver.common.by import By

      # 導入已封裝的類 Base.py

      from Base import Base

      class Test_Base:

          def __init__(self):

              desired_caps = {}

              # 手機 系統資訊

              desired_caps['platformName'] = 'Android'

              desired_caps['platformVersion'] = '5.1'

              # 裝置号

              desired_caps['deviceName'] = '192.168.56.101:5555'

              # 包名

              desired_caps['appPackage'] = 'com.android.settings'

              # 啟動名

              desired_caps['appActivity'] = '.Settings'

              # 允許輸入中文

              desired_caps['unicodeKeyboard'] = True

              desired_caps['resetKeyboard'] = True

              # 手機驅動對象

              self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)

          def test(self):

              # 搜尋按鈕

              search_button = (By.ID,"com.android.settings:id/search")

              # 搜尋輸入框

              search_text = (By.ID,"android:id/search_src_text")

              # 搜尋框傳回按鈕

              search_return_button = (By.CLASS_NAME,"android.widget.ImageButton")

              # 執行個體化二次封裝的Base類

              base_object = Base(self.driver)

              # 點選搜尋輸入框

              base_object.click_element(search_button)

              # 搜尋框内輸入123

              base_object.input_text(search_text,123)

              # 點選搜尋框傳回按鈕

              base_object.click_element(search_return_button)

              # 退出driver對象

              self.driver.quit()

      if __name__ == "__main__":

          Test_Base().test()

3.頁面元素操作封裝(一)

    将頁面元素定位和元素操作封裝在一個類檔案中.

封裝步驟

确定好要封裝的頁面操作

  業務場景:

      1.進入設定

      2.點選搜尋按鈕

      3.輸入123

      4.點選搜尋框傳回按鈕

需要用到哪些元素和定位方法

  # 搜尋按鈕

  search_button = (By.ID, "com.android.settings:id/search")

  # 搜尋輸入框

  search_text = (By.ID, "android:id/search_src_text")

  # 搜尋框傳回按鈕

  search_return_button = (By.CLASS_NAME,"android.widget.ImageButton")

依賴的定位方法

  使用二次封裝的方法,Base.py檔案

頁面封裝

  編寫搜尋操作類:search_page.py

      from selenium.webdriver.common.by import By

      # 導入基礎定位封裝包

      from Base import Base

      class Search_Page:

          def __init__(self,driver):

              # 傳如driver對象

              self.driver = driver

              # 執行個體化二次封裝的類,用到封裝好的操作函數

              self.base_object = Base(self.driver)

              # 搜尋按鈕

              self.search_button = (By.ID, "com.android.settings:id/search")

              # 搜尋輸入框

              self.search_text = (By.ID, "android:id/search_src_text")

              # 搜尋框傳回按鈕

              self.search_return_button = (By.CLASS_NAME,"android.widget.ImageButton")

          def input_search_text(self,text):

              # text: 需要輸入的内容

              # 封裝搜尋按鈕的輸入操作

              # 點選設定中搜尋按鈕

              self.base_object.click_element(self.search_button)

              # 在搜尋輸入框内輸入123

              self.base_object.input_text(self.search_text,text)

              # 點選搜尋框傳回按鈕

              self.base_object.click_element(self.search_return_button)

  編寫測試檔案: test.py

      from appium import webdriver

      # 導入封裝好的頁面類

      from search_page import Search_Page

      class Test_Base:

          def __init__(self):

              desired_caps = {}

              # 手機 系統資訊

              desired_caps['platformName'] = 'Android'

              desired_caps['platformVersion'] = '5.1'

              # 裝置号

              desired_caps['deviceName'] = '192.168.56.101:5555'

              # 包名

              desired_caps['appPackage'] = 'com.android.settings'

              # 啟動名

              desired_caps['appActivity'] = '.Settings'

              # 允許輸入中文

              desired_caps['unicodeKeyboard'] = True

              desired_caps['resetKeyboard'] = True

              # 手機驅動對象

              self.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)

          def test(self):

              # 執行個體化頁面封裝類

              sp = Search_Page(self.driver)

              # 調用操作類

              sp.input_search_text(123)

              # 退出driver對象

              self.driver.quit()

      if __name__ == "__main__":

          Test_Base().test()

問題

  1.若我要完成Base基礎類的導入,需要在每個頁面的封裝類内執行個體化Base類,

      并需要執行個體化對象引用Base類内部方法。

      即:

          self.driver = driver

          self.base_object = Base(self.driver)

  2.若我們有多個測試函數檔案,需要在每個檔案中都聲明一次driver,

      重複代碼太多,并且測試類内部備援代碼過多。

4.頁面元素操作封裝(二)

    通過類繼承的方式完成頁面的封裝

頁面封裝

  業務場景:

      1.進入設定

      2.點選搜尋按鈕

      3.輸入123

      4.點選搜尋框傳回按鈕

  頁面封裝類:search_page.py

      from selenium.webdriver.common.by import By

      # 導入基礎定位封裝包

      from Base import Base

      class Search_Page(Base):

          def __init__(self,driver):

              Base.__init__(self,driver) # 父類初始化方法

              # 搜尋按鈕

              self.search_button = (By.ID, "com.android.settings:id/search")

              # 搜尋輸入框

              self.search_text = (By.ID, "android:id/search_src_text")

              # 搜尋框傳回按鈕

              self.search_return_button = (By.CLASS_NAME,"android.widget.ImageButton")

          def input_search_text(self,text):

              # text: 需要輸入的内容

              # 封裝搜尋按鈕的輸入操作

              # 點選設定中搜尋按鈕

              self.click_element(self.search_button) # 子類繼承父類的所有方法

              # 在搜尋輸入框内輸入

              self.input_text(self.search_text,text)

              # 點選搜尋框傳回按鈕

              self.click_element(self.search_return_button)

獨立手機驅動對象方法

  統一管理手機驅動對象的初始化

    建立手機驅動對象檔案:Init_Driver.py

    代碼:

        from appium import webdriver

        def init_driver():

            # 服務端啟動參數

            desired_caps = {}

            # 手機 系統資訊

            desired_caps['platformName'] = 'Android'

            desired_caps['platformVersion'] = '5.1'

            # 裝置号

            desired_caps['deviceName'] = '192.168.56.101:5555'

            # 包名

            desired_caps['appPackage'] = 'com.android.settings'

            # 啟動名

            desired_caps['appActivity'] = '.Settings'

            # 允許輸入中文

            desired_caps['unicodeKeyboard'] = True

            desired_caps['resetKeyboard'] = True

            # 手機驅動對象

            driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)

            return driver # 傳回driver對象

測試腳本編寫

    代碼實作: test.py

        # 導入封裝好的頁面類

        from cup.search_page import Search_Page

        # 導入獨立的手機驅動對象

        from cup.Init_Driver import init_driver

        class Test_Base:

            def __init__(self):

                self.driver = init_driver()

            def test(self):

                # 示例化頁面封裝類

                sp = Search_Page(self.driver)

                # 調用操作類

                sp.input_search_text(123)

                # 退出driver對象

                self.driver.quit()

        if __name__ == "__main__":

            Test_Base().test()

自動化之PO模式(二)

5.PO模式項目管理

目錄結構

    清晰的目錄結構,友善代碼子產品化管理和他人解讀。

    常用目錄結構:

        App_Project # 項目名稱

          - Basic # 存儲基礎設施類

              - __init__.py # 空檔案

              - Init_Driver.py # 手機驅動對象初始化

              - Base.py # 方法的二次封裝

              - read_data.py #資料解析讀取方法

          - Page # 存儲封裝頁面檔案

              - __init__.py # 存儲頁面元素

              - search_page.py # 封裝頁面元素的操作方法

          - Data # 存儲資料檔案

              - search_data.yaml(也可以是其他檔案比如txt,excel,json,資料庫等)

          - Test # 存儲測試腳本目錄

              - test_search.py # 測試搜尋檔案

Basic目錄檔案代碼

    1.Basic/Init_Driver.py

    from appium import webdriver

    def init_driver():

        # 服務端啟動參數

        desired_caps = {}

        # 手機 系統資訊

        desired_caps['platformName'] = 'Android'

        desired_caps['platformVersion'] = '5.1'

        # 裝置号

        desired_caps['deviceName'] = '192.168.56.101:5555'

        # 包名

        desired_caps['appPackage'] = 'com.android.settings'

        # 啟動名

        desired_caps['appActivity'] = '.Settings'

        # 允許輸入中文

        desired_caps['unicodeKeyboard'] = True

        desired_caps['resetKeyboard'] = True

        # 手機驅動對象

        driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)

        return driver

    2.Basic/Base.py

    from selenium.webdriver.support.wait import WebDriverWait

    class Base(object):

        def __init__(self,driver):

            self.driver = driver

        def find_element(self,loc,timeout=10):

            '''

                二次封裝find_element方法,增加了顯示等待和簡化參數傳遞

            '''

            # 原生方法:find_element(by=By.ID, value=None),需要傳遞兩個值

            # *loc 将傳入(By.XX, "value")解包為兩個單獨的值,滿足find_element方法的參數傳遞

            return WebDriverWait(self.driver, timeout).until(lambda x: x.find_element(*loc))

        def click_element(self,loc):

            '''

                封裝點選操作函數

            '''

            self.find_element(loc).click()

        def input_text(self,loc,text):

            '''

                封裝輸入操作函數

            '''

            self.fm = self.find_element(loc)

            self.fm.clear() # 需要先清空輸入框,防止有預設内容

            self.fm.send_keys(text)

Page目錄檔案代碼

    1.Page/__init__.py

    from selenium.webdriver.common.by import By # selenium原生定位政策集

    '''

        設定頁面

    '''

    # 搜尋按鈕

    search_button = (By.ID, "com.android.settings:id/search")

    # 搜尋輸入框

    search_text = (By.ID, "android:id/search_src_text")

    # 搜尋框傳回按鈕

    search_return_button = (By.CLASS_NAME,"android.widget.ImageButton")

    2.Page/search_page.py

    # 導入基礎定位封裝包

    from Basic.Base import Base

    import Page

    class Search_Page(Base):

        def __init__(self,driver):

            Base.__init__(self,driver) # Base類的初始化方法

        def input_search_text(self,text):

            '''

                封裝搜尋按鈕的輸入操作

            '''

            # 點選設定中搜尋按鈕

            self.click_element(Page.search_button) # 傳入的__init__.py檔案聲明的search_button變量

            # 在搜尋輸入框内輸入

            self.input_text(Page.search_text,text) # 傳入的__init__.py檔案聲明的search_text變量

            # 點選搜尋框傳回按鈕

            self.click_element(Page.search_return_button) # 傳入的__init__.py檔案聲明的search_return_button變量

Test目錄檔案代碼

    1.test_search.py

    # 導入封裝好的頁面類

    from Page.search_page import Search_Page

    # 導入獨立的手機驅動對象

    from Basic.Init_Driver import init_driver

    import time

    class Test_Base:

        def __init__(self):

            self.driver = init_driver()

        def test(self):

            # 示例化頁面封裝類

            sp = Search_Page(self.driver)

            # 調用操作類

            sp.input_search_text(123)

            # 退出driver對象

            self.driver.quit()

    if __name__ == "__main__":

        Test_Base().test()

繼續閱讀