面向对象的特性:封装、继承、多态。在自动化中一样适用,Selenium自动化测试中有一个名字常常被提及PageObject(思想与面向对象的特性相同),通过PO模式可以大大提高测试用例的维护效率。
##传统测试脚本的弊端
测试脚本分离,维护成本高
可扩展性差
复用性低等
PageObject设计模式
selenium自动化测试框架之PO设计模式
PO的核心要素:
在PO模式中抽象封装成一个BasePage类,该基类应该拥有一个只实现webdriver实例的属性。
每个一个page都继承BasePage,通过driver来管理本page中元素,将page中的操作封装成一个个的方法。
TestCase继承unittest.Testcase类,并且依赖page类,从而实现相应的测试步骤。·
案例
基础案例
前面基础场景选取的是QQ邮箱、写信操作!
class DriverUtil(object):
"""定义浏览器工具类"""
_driver = None
# 添加自动退出标记
_auto_quit = True
@classmethod
def get_driver(cls):
"""获取浏览器对象方法"""
if cls._driver is None:
# 初始化浏览器对象
cls._driver = webdriver.Chrome()
# 设置窗口最大化
cls._driver.maximize_window()
# 设置隐式等待
cls._driver.implicitly_wait(10)
# 打开链接
cls._driver.get('https://mail.qq.com/')
return cls._driver
@classmethod
def quit_driver(cls):
"""退出浏览器对象方法"""
if cls._auto_quit and cls._driver:
cls._driver.quit()
cls._driver = None
@classmethod
def auto_quit(cls, auto_quit):
"""开关浏览器退出方法"""
cls._auto_quit = auto_quit
将获取的驱动对象都封装到一个类中,有要使用时,调用当前文件就可。
from selenium.webdriver.common.by import By
class UIElements:
"""管理所有页面元素"""
"""qq邮箱登陆页面"""
Account_password_login_btn = (By.ID, 'switcher_plogin') # 账号密码登陆按钮
input_user_name = (By.ID, 'u') # 账号输入框
input_password = (By.ID, 'p') # 密码输入框
login_button = (By.ID, 'login_button') # 登录按钮
"""qq邮箱首页"""
write_a_letter_btn = (By.XPATH, '//*[@id="composebtn"]') # 写信按钮
inbox_btn = (By.ID, 'folder_1') # 收件箱按钮
"""写信页面"""
Recipient_input_box = (By.XPATH, "//*[@id='toAreaCtrl']/div[2]/input") # 收件人输入框
Subject_input_box = (By.ID, 'subject') # 主题输入框
text_input = (By.XPATH, '/html/body') # 正文输入框
send_btn = (By.XPATH, '//*[@id="toolbar"]/div/a[1]') # 发送按钮
Return_homepage = (By.ID, 'btnbackl') # 返回邮箱首页按钮
"""收件箱页面"""
apple_email = (
By.XPATH, '//*[@id="div_showlastweek"]/table[1]/tbody/tr/td[3]/table/tbody/tr/td[1]/nobr/span') # 具体邮件
user_email = (
By.XPATH, '//*[@id="mailContentContainer"]/table/tbody/tr/td/div[1]/table/tbody/tr[4]/td/table/tbody/tr[1]/td/table/tbody/tr[1]/td[1]/a') #页面邮箱号元素
所有页面需要用到的元素定位属性,放到一起方便管控,要使用时调用此类即可,如页面元素修改,及只要修改此页面元素的属性值即可。
from utils import DriverUtil
class Base(object):
"""page操作类"""
def __init__(self):
self.driver = DriverUtil.get_driver()
def get_element(self, loc):
"""
单个元素定位(利用拆包获取元组属性值)
:param loc: 元素对象定位方法类型和属性值
:return: 元素对象
"""
return self.driver.find_element(*loc)
def get_elements(self, loc):
"""
定位一组元素
:param loc: (By.ID,id属性值) (By.CLASS_NAME,class属性值) (By.XPATH,xpath属性值)
:return:元素定位对象列表
"""
return self.driver.find_elements(*loc)
def click_element(self, loc):
"""
点击元素
:param loc: (By.ID,id属性值) (By.CLASS_NAME,class属性值) (By.XPATH,xpath属性值)
:return:
"""
self.get_element(loc).click()
def send_element(self, loc, text):
"""
输入文本内容
:param loc: (By.ID,id属性值) (By.CLASS_NAME,class属性值) (By.XPATH,xpath属性值)
:param text: 输入文本内容
:return:
"""
# 定位元素
input_text = self.get_element(loc)
# 清空输入框
input_text.clear()
# 输入元素
input_text.send_keys(text)
def get_text_information(self, loc):
"""
获取当前元素的文本信息
:param loc: (By.ID,id属性值) (By.CLASS_NAME,class属性值) (By.XPATH,xpath属性值)
:return:
"""
return self.get_element(loc).text
此类中为操作事件方法,现已有的点击、输入、获取改元素上的文本信息,可结合自身使用,自主添加各种方法。(需要使用方法时调用此类即可)
"""qq邮箱登陆页面"""
from base.base import Base
from page.UIElements import UIElements
import json
import config
import logging
class EmailLoginPage(Base):
def __init__(self):
super().__init__()
def account_password_login(self):
"""点击账号密码登陆"""
self.click_element(UIElements.Account_password_login_btn)
def input_username(self, username):
"""输入用户名"""
self.send_element(UIElements.input_user_name, username)
def input_password(self, pwd):
"""输入密码"""
self.send_element(UIElements.input_password, pwd)
def click_login_btn(self):
"""点击登陆按钮"""
self.click_element(UIElements.login_button)
页面类,把每个页面分开,每个页面写入需操作的方法,按页面分(这边举例的是登陆页面上的所有操作方法和步骤)
class TestLogin(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.driver = DriverUtil.get_driver() # 获取浏览器驱动对象
cls.email_login_page = EmailLoginPage() # 获取登陆页驱动对象
cls.driver.switch_to.frame("login_frame") # 切换至输入框窗口
cls.email_login_page.account_password_login() # 点击使用账号密码登陆
@classmethod
def tearDownClass(cls):
DriverUtil.quit_driver() # 退出浏览器
def tearDown(self):
time.sleep(3)
def test_login(self ):
self.email_login_page.input_username(“aaaa”) # 输入用户名
self.email_login_page.input_password("11111") # 输入密码
self.email_login_page.click_login_btn() # 点击登陆
# 设置睡眠,等待页面标题的加载
time.sleep(2)
# 获取页面标题
title = self.driver.title
# 断言判断测试结果
self.assertIn("断言结果", title)
脚本类,执行上述页面的方法,在此处运行脚本
在编写测试用例testcase的代码,主要是测试用例执行的功能,可以按照场景编写每个用例,也可以实现之前讲述的数据分离驱动测试数据。来进行各种读取和调用,通过unittest 框架来执行测试用例继承unittest.TestCase
后面会使用HTMLTestRunner 生成测试报告,邮件发送及PO设计模式的测试框架
————————————————