關於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
運行代碼:
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()