关于PO模型遇到的一个问题
背景:基于pytest+poium实现UI自动化
问题:先看下我们基于PO思想封装的一个页面类,每个行为我们都把它处理为一个类方法,再看用例层,传入全局browser(全局浏览器驱动实例)给类Search_baidu,执行用例的时候会报一个错误:
AttributeError: ‘NoneType’ object has no attribute ‘find_elements’
# 页面类
from poium import Page, NewPageElement
class Search_baidu(Page):
"""百度首页页面元素定位"""
@classmethod
def input_search(cls, search_key):
input_text = NewPageElement(css='input[name="wd"]', describe="输入搜索关键词")
input_text.send_keys(search_key)
@classmethod
def click_search(cls):
click_btn = NewPageElement(css='input[class$="s_btn"]', describe="点击搜索")
click_btn.click()
# 用例层
"""使用poium库实现百度搜索功能"""
import pytest
from page_handle.baidu_demo.baidu_search import Search_baidu
class TestBaidu:
"""百度搜素"""
def test_baidu_search_case2(self, browser, baidu_url):
page_baidu = Search_baidu(browser)
page_baidu.get(baidu_url)
page_baidu.input_search('pytest')
page_baidu.click_search()
原因:基于上面报的错误,直接追踪到NewPageElement类,看下部分源码发现,NewPageElement类其实是一个数据描述符,通过get(),拿到一个browser实例,再回到我们的的页面类,NewPageElement代理非类属性,所以无法触发get(),也就无法拿到browser实例,只有代理另一个类的类属性才能触发get()
# NewPageElement类部分源码
class NewPageElement(object):
"""
new Page element class
"""
def __init__(self, timeout=5, describe="undefined", index=0, **kwargs):
self.timeout = timeout
self.index = index
self.desc = describe
if not kwargs:
raise ValueError("Please specify a locator")
if len(kwargs) > 1:
raise ValueError("Please specify only one locator")
self.kwargs = kwargs
self.k, self.v = next(iter(kwargs.items()))
if self.k not in LOCATOR_LIST.keys():
raise FindElementTypesError("Element positioning of type '{}' is not supported.".format(self.k))
def __get__(self, instance, owner):
if instance is None:
return None
Browser.driver = instance.driver
return self
def __set__(self, instance, value):
self.__get__(instance, instance.__class__)
self.send_keys(value)
def __find_element(self, elem):
"""
Find if the element exists.
"""
logging.info("Browser.driver调试!!: {}".format(Browser.driver))
for i in range(self.timeout):
elems = Browser.driver.find_elements(by=elem[0], value=elem[1])
if len(elems) == 1:
logging.info("Find element: {by}={value} ".format(
by=elem[0], value=elem[1]))
break
elif len(elems) > 1:
logging.info("Find {n} elements through: {by}={value}".format(
n=len(elems), by=elem[0], value=elem[1]))
break
else:
sleep(1)
else:
error_msg = "Find 0 elements through: {by}={value}".format(by=elem[0], value=elem[1])
logging.error(error_msg)
raise NoSuchElementException(error_msg)
解决问题:因为NewPageElement是数据描述符,把描述符定义为这个类的类属性,则解决问题
备注:更多关于描述符知识点见python描述符
_
设置浏览器启动语言
有时候开启浏览器需要特别的语言版本,比如,英文的,中文的。
测试时候发现,机器默认启动的是系统语言对应的浏览器,我们的被测网站的中文的,而系统是英文的,开启的浏览器就是英文的,提交的某些数据按照英文的格式提交了,导致数据报错,那么我们就需要设置浏览器启动语言。
Chrome 需要通过ChromeOptions来解决,设置如下参数(—lang=zh-CN):
def web_driver():
"""
定义浏览器驱动
:return:
"""
driver = None
chrome_options = CH_Options()
if Config.DRIVER_TYPE == 'chrome':
# 界面模式
chrome_options.add_argument('--ignore-certificate-errors')
driver = webdriver.Chrome(options=chrome_options)
elif Config.DRIVER_TYPE == 'chrome_headless':
# 无头模式
chrome_options.add_argument('--headless')
chrome_options.add_argument('--lang=zh-CN') # 设置chrome启动语言为中文
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--window-size=1680x1050')
chrome_options.add_argument('--ignore-certificate-errors')
driver = webdriver.Chrome(options=chrome_options)
else:
raise NameError("driver 浏览器驱动定义错误!")
driver.maximize_window()
driver.implicitly_wait(10)
return driver
记一次关于如何启动麦克风权限
chrome启动参数中增加 use-fake-device-for-media-stream、use-fake-ui-for-media-stream
def web_driver():
"""
定义浏览器驱动
:return:
"""
chrome_options = CH_Options()
if Config.DRIVER_TYPE == 'chrome':
# 界面模式
chrome_options.add_argument('--ignore-certificate-errors') # 忽略与证书相关的错误
chrome_options.add_argument("allow-file-access-from-files") # 允许打开本地文件
# --use-fake-device-for-media-stream 使用假设备进行MediaStream替换实际的摄像头和麦克风
# --use-fake-ui-for-media-stream 通过选择媒体流的默认设备来绕过媒体流信息量。与--use-fake-device-for-media-stream一起使用
chrome_options.add_argument("use-fake-device-for-media-stream")
chrome_options.add_argument("use-fake-ui-for-media-stream")
driver = webdriver.Chrome(options=chrome_options)
elif Config.DRIVER_TYPE == 'chrome_headless':
# 无头模式
chrome_options.add_argument('--headless')
chrome_options.add_argument('--lang=zh-CN') # 设置chrome启动语言为中文
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--window-size={}'.format(screen_size()))
chrome_options.add_argument('--ignore-certificate-errors')
driver = webdriver.Chrome(options=chrome_options)
logger.info("当前系统分辨率为{}".format(screen_size()))
else:
raise NameError("driver 浏览器驱动定义错误!")
driver.maximize_window()
driver.implicitly_wait(10)
return driver