web自動化測試第22步:POM設計模式的實現

關於pom設計模式(project Object model/PageObject),我的理解是一種底層、邏輯、用例的分層,在項目還沒有開發出來時,就可以開始寫UI自動化腳本了,在開發完成後,再進行元素定位的適配以及調試;而且也可以多人共同維護開發腳本,更方便大家合作。這一節主要來介紹一下如何從零開始搭建這幾個層級。

層級結構

一、driver層的封裝

這一層主要是對於webdriver方法的封裝,這裏來舉一個栗子,最常用的定位方法,之前講過統一定位方法的三種傳參格式:webdriver的所有定位方法,使用find_element()方法通過BY類、字符串、元組三種方法傳遞定位類型和數據,這裏我使用元組的形式(例如locator = ("id","name_box"))來傳遞參數。

1.1 定位元素方法封裝示例

這個定位元素的公共方法中,加了很多東西;如果每次定位的時候寫這些異常捕獲、打印操作的話,那麼程序會非常臃腫,所以需要單獨提出來,每次需要定位的時候統一調用這個方法。

  • 有一個入參locator,格式爲("定位類型","定位參數值"),返回我們所定位到的元素
  • 加入了元素等待,並判斷該元素是否存在
  • 對於關鍵信息的打印輸出,方便定位監控
  • 加入了異常捕獲,定位失敗後可以繼續執行程序
    def find_element(self, *locator):
        try:
            print("定位元素:%s" % (locator,))
            return WebDriverWait(self.driver, 10).until(EC.presence_of_element_located(locator))
        except Exception as msg:
            print(u"%s 頁面中未能找到 %s 元素" % (self, locator))
            print("錯誤信息%s" % msg)

1.2 封裝類的初始化

對於webdriver的封裝,我們要先創建一個class,這樣方便我們繼承調用這些封裝的方法。在class中,我這裏設計了一個初始化,每次調用封裝的driver時,傳遞三個參數,一個必填項:driver、兩個非必填項:page_url、page_title,我這樣的想法是每次引用這個封裝類時,傳遞一個driver進來,如果有打開網址頁面的需要,則傳遞網址和網址頁面的title,這樣也可以做一次校驗。

def __init__(self, driver, page_url=None, page_title=None):
        self.page_url = page_url
        self.page_title = page_title
        self.driver = driver
        self.driver.maximize_window()
        self.driver.implicitly_wait(30)

 

二、page層書寫

page類在繼承我們封裝的webdriver後,主要寫具體的操作步驟,例如輸入登錄名、輸入登錄密碼、點擊登錄按鈕等操作。

2.1繼承pagedriver並初始化

這裏的page層要繼承pagedriver的類Action,然後在page層的初始化中,初始化Action。

from common.pagedriver import Action


class Login(Action):


    def __init__(self, driver, page_url=None, page_title=None):
        Action.__init__(self, driver, page_url, page_title)

2.2 操作步驟

比如我要寫打開頁面、輸入用戶名這兩個方法:

其中元素定位放在類變量中,而登錄賬號我們放在case層來輸入。

from common.pagedriver import Action

class Login(Action):
    input_name_loc = ("xpath", "//input[@placeholder='郵箱帳號或手機號碼']")
    frame_loc = (0)

    def __init__(self, driver, page_url=None, page_title=None):
        Action.__init__(self, driver, page_url, page_title)

    def open(self):
        """打開頁面"""
        self._open(self.page_url, self.page_title)

    def input_name(self, login_name):
        """輸入登錄名"""
        self.send_keys(self.input_name_loc, login_name)

 

三、case層調用

終於到了第三層,這裏我們要做的就是把page層的方法,像搭積木一樣搭起來,並且連成完整的操作。

3.1 使用unittest,並初始化數據

在unittest的框架基礎上,主要是在setUp()方法中初始化我們的數據,例如網址、賬號、driver的初始化。

import unittest
from selenium import webdriver


class Demo(unittest.TestCase):

    def setUp(self):
        self.url = "https://mail.163.com/"
        self.title = "網易"
        self.user_name = ""  # 登錄賬戶
        self.user_password = ""  # 登錄密碼
        self.driver = webdriver.Chrome()

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


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

3.2 調用方法,完成用例

首先我們引用page層,然後使用page層的方法搭建case。


from page.login_page import Login

    def test_login(self):
        login_page = Login(self.driver, self.url, self.title)
        login_page.open()
        login_page.input_name(self.user_name)

四、實例演示:登錄163網易郵箱

大功告成!!這裏我通過上述的分層步驟,演示登錄163郵箱的操作,登錄後通過斷言登陸成功頁面title,來判斷是否登錄成功。

運行結果:

打開網址:https://mail.163.com/
網址預期標題: 網易
定位元素:('xpath', "//input[@placeholder='郵箱帳號或手機號碼']")
輸入值:
定位元素:('xpath', "//input[@placeholder='輸入密碼']")
輸入值:
定位元素:('xpath', "//input[@placeholder='輸入密碼']")
輸入值:
(26封未讀) 網易郵箱6.0版
.
----------------------------------------------------------------------
Ran 1 test in 202.126s

OK

運行代碼:

pagedriver.py

from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait


class Action(object):
    """
     Action封裝所有頁面都公用的方法
    """

    # 初始化driver、url、title等
    def __init__(self, driver, page_url=None, page_title=None):
        self.page_url = page_url
        self.page_title = page_title
        self.driver = driver
        self.driver.maximize_window()
        self.driver.implicitly_wait(30)

    def open(self):
        """
        定義open方法,調用_open()進行打開鏈接
        """
        self._open(self.page_url, self.page_title)

    def on_page(self, page_title):
        """
        使用current_url獲取當前窗口Url地址,進行與配置地址作比較,返回比較結果(True False)
        """
        return page_title in self.driver.title

    def _open(self, page_url, page_title):
        """
        打開頁面,校驗頁面鏈接是否加載正確
        """
        # 使用get打開訪問鏈接地址
        if page_url and page_title is not None:
            self.driver.get(page_url)
            print("打開網址:%s" % page_url)
            print("網址預期標題: %s" % page_title)
            # 使用assert進行校驗,打開的鏈接地址是否與配置的地址一致。調用on_page()方法
            assert self.on_page(page_title), u"打開頁面%s失敗" % page_url

    def find_element(self, *locator):
        try:
            print("定位元素:%s" % (locator,))
            return WebDriverWait(self.driver, 20).until(EC.presence_of_element_located(locator))
        except Exception as msg:
            print(u"%s 頁面中未能找到 %s 元素" % (self, locator))
            print("錯誤信息%s" % msg)

    def send_keys(self, locator, value, clear_first=True):
        """
        重寫定義send_keys方法
        """
        element = self.find_element(*locator)
        if clear_first:
            element.clear()
            element.send_keys(value)
        else:
            element.send_keys(value)
        print("輸入值:%s" % value)

    def switch_frame(self, frame_loc):
        """
        切換frame,
        :param frame_loc:id、name、element、index
        :return:
        """
        self.driver.switch_to.frame(frame_loc)

 

login_page.py

from common.pagedriver import Action
from selenium.webdriver.common.keys import Keys


class Login(Action):
    input_name_loc = ("xpath", "//input[@placeholder='郵箱帳號或手機號碼']")
    input_password_loc = ("xpath", "//input[@placeholder='輸入密碼']")
    enter_login_loc = Keys.ENTER
    frame_loc = (0)

    def __init__(self, driver, page_url=None, page_title=None):
        Action.__init__(self, driver, page_url, page_title)

    def open(self):
        """打開頁面"""
        self._open(self.page_url, self.page_title)

    def change_frame(self):
        """切換frame"""
        self.switch_frame(self.frame_loc)

    def input_name(self, login_name):
        """輸入登錄名"""
        self.send_keys(self.input_name_loc, login_name)

    def input_password(self, login_password):
        """輸入密碼"""
        self.send_keys(self.input_password_loc, login_password)

    def enter_login(self):
        """模擬登陸點擊回車"""
        self.send_keys(self.input_password_loc, self.enter_login_loc, False)

    def get_login_message(self):
        """獲取登錄後的信息以斷言"""
        return self.driver.title

 

test_163_login.py

# -*- coding: utf-8 -*-
import unittest
from time import sleep
from page.login_page import Login
from selenium import webdriver


class Demo(unittest.TestCase):

    def setUp(self):
        self.url = "https://mail.163.com/"
        self.title = "網易"
        self.user_name = ""  # 登錄賬戶
        self.user_password = ""  # 登錄密碼
        self.driver = webdriver.Chrome()

    def test_wangyi_login(self):
        """登錄網易郵箱"""
        login_page = Login(self.driver, self.url, self.title)
        login_page.open()
        login_page.change_frame()
        sleep(3)
        login_page.input_name(self.user_name)
        login_page.input_password(self.user_password)
        sleep(2)
        login_page.enter_login()
        sleep(5)
        print(login_page.get_login_message())
        assert "網易郵箱6.0版" in login_page.get_login_message()

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


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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章