PO模式
PO模式:指在编写自动化代码的时候,以每一个页面为对象建立一个py文件的设计模式,PO(英文名称:Page Object),每一个页面都对应的有一个PO类,且在这个页面的类中,包含了对该页面的的元素定位以及操作方法,以便于提高代码的可读性和可维护性。
po设计模型可分为三成:
- 表现层:页面中可捡的元素(元素的定位编写)
- 操作层:对页面可见元素的操作,例如点击,输入文本,获取文本(元素的基本操作,基类封装)
-
业务层:表现层和操作层组合而成的,由操作层操作表现层的元素来实现某些功能即业务层需要完成的
测试用例:结合以上三层,操作多个页面的元素完成指定的功能,关系如下所示:PO模型项目结构如下:请自行在本地建立如下的项目结构
项目结构
基类的封装

基类封装
浏览器封装
步骤:
1、获取浏览器的方法get_driver
2、通过参数控制浏览器的默认类型(兼容性测试)
3、通过参数控制浏览器的模式,可以无头运行
4、通过参数控制隐式等待时间(设置隐式等待可以避免元素未加载出来就被操作了的情况)
5、优化:单例实现(参数化登录用例发现打开多个页面后改进)
封装如下:
from selenium import webdriver
from configs.env import Env
class Single(object):
'''
单例是一种设计模式
1.直接用
2.要去理解_new__init_type
3.单例的应用场景:log、自动化测试的时候浏览器、配置器、播放器
'''
_instance = None # 实例
def _new_(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
class Single1(object):
def _new_(cls, *args, **kwargs):
if not hasattr(cls, ' instance'): # instance 私有的
cls._instance = super().__new__(cls)
return cls._instance
class CommDriver(Single):
"""
功能:打开一个浏览器
1.测试多种浏览器
2.配置参数:浏览器类型,是否有头,隐式等待时间
"""
driver = None
def get_driver(self, browser_type=Env.BROWSER_TYPE,
headless_flag=Env.HEADLESS_FLAG):
'''
:param browser_type:浏览器类型,取配置文件中的值作为默认值
:param headless flag:是否有头,取配置文件中的值作为默认值
:return: 返回一个浏览器对象
'''
if self.driver is None: # 如果没有打开过浏览器,就去打开
if headless_flag: # 如果有头模式
if browser_type == 'chrome':
self.driver = webdriver.Chrome()
elif browser_type == 'firefox':
self.driver = webdriver.Firefox()
# 其他的浏览器测试可以再添加
else:
raise Exception(f'暂不支持当前的{browser_type}')
else:
if browser_type == 'chrome':
__option = webdriver.ChromeOptions() # _option前面_是建议私有
__option.add_argument('--headless') # 添加一个--headless参数
self.driver = webdriver.Chrome(options=self.__option)
elif browser_type == 'firefox':
option = webdriver.FirefoxOptions()
option.add_argument('--headless')
self.driver = webdriver.Firefox(options=self.__option)
else:
raise Exception(f'暂不支持当前的{browser_type}')
self.driver.maximize_window() # 最大化
self.driver.implicitly_wait(Env.IMPLICITLY_WAIT_TIME) # 隐式等待
return self.driver # 如果打开过了,就直接返回
if __name__ == '__main__':
brower = CommDriver().get_driver().get('www.baidu.com')
配置文件(configs/env)如下:设置常见的参数,后续可能会新增
class Env:
BROWSER_TYPE = 'chrome' # CTRL+SHIFT+U 大写 #默认浏览器类型
HEADLESS_FLAG = True # 默认是有头 # True是有头
PAGE_LOAD_TIMEOUT = 30 # 页面加载超时
IMPLICITLY_WAIT_TIME =30 # 隐式等待30
HOST = 'http://49.4.78.178:28/metric/view/login.html' # 被测网站首页
GET_ELEMENT_TIMEOUT = 5 # 显式等待默认超时时间
SMP_FREQUENCY = 0.5 # 显式等待默认轮询时间
MAINPAGE_URL = 'http://49.4.78.178:28/metric/view/HTML/page.html' # 登录后首页的URL
基类封装(常见操作)
基类分装需要完成如下操作:
打开浏览器,输入网址,定位元素(获取元素添加等待,以免出现定位不到元素的情况),输入文本,点击元素(等待后点击)
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from Common.Commom import CommDriver
class BasePage():
'''
一般步骤:打开浏览器-->输入网址-->定位元素-->操作元素(输入文本/点击元素)
'''
def __init__(self):
self.driver = CommDriver().get_driver() # 打开浏览器的方法
self.locators = get_yaml_data(SMP_Path.common_path / 'allelements.yaml')[self.__class__.__name__] # 初始化就打开定位元素的
# 把元素的名字设置为当前页面的属性
for elementname, locator in self.locators.items():
# allelements.yaml为所有页面的元素集合
# locators 所有的定位元素,是一个字典key:value 分别对应 elementname,locator
# locators = {
# 'login_button': ['css selector', '.btn_sign_up'],
# 'message_text': ['id', 'content_ics'],
setattr(self, elementname, locator)
def open_url(self, url):
self.driver.get(url)
def get_element(self,locator,timeout=Env.GET_ELEMENT_TIMEOUT,
smp_frequency=Env.SMP_FREQUENCY, desc='') -> WebElement:
'''
locator: 定位器,如:(By.ID,'username')['id','username']
return:返回元素
'''
try:
return WebDriverWait(self.driver, timeout, smp_frequency). \
until(EC.visibility_of_element_located(locator))
# return self.driver.find_element(*locator)
except:
# 定位不到元素时,截图:文件的命名(定位哪一个元素+时间)
curtime = time.strftime('%Y%m%d%H%M%S')
self.driver.save_screenshot(f'{SMP_Path.screenshots_path} / {desc}{curtime}.png')
def input_text(self, locator, text, append=False):
'''
locator:定位器
text:输入的文本
append:是否是追加输入,Ture追加输入,False清空后输入
'''
if not append:
self.get_element(locator).clear() # 如果存在文本,则清空
self.get_element(locator).sendkeys(text) # 输入文本信息
else:
self.get_element(locator).sendkeys(text)
def click_element(self, locator):
self.get_element(locator).click()
def get_element_text(self, locator):
return self.get_element(locator).text
def wait_click_element(self, locator): # 等待后点击元素
WebDriverWait(self.driver, 5, 0.5).until(EC.visibility_of_element_located(locator)).click() # 设置超市时间和轮询时间
def wait_click_element_text(self, locator): # 等待后获取元素文本
return WebDriverWait(self.driver, 5, 0.5).until(EC.visibility_of_element_located(locator)).text