问题
https://selenium-python-zh.readthedocs.io/en/latest/page-objects.html#id4 . 老师这个页面,它是用python的描述器进行页面元素的编写,不需要每个元素在调用find方法去进行获取,这样把页面对象/页面元素/页面类分离开,真实工作中会这样使用吗
使用描述器不过是一种语法技巧,可以看成是一种特殊的缩写方式,与具体的设计思想无关,这类的技巧总结如下
- 使用get set模拟获取文本与输入
- 使用python装饰器或者java的注解完成通用方法的增强封装
首先简单的场景是可以这样设计的,但是get set没法模拟一个元素的所有行为,比如获得他的某个属性get_attribute,除了输入外,还同时有滑动和点按效果。最后还是会回到普通的方法定义。装饰器和注解也有一定的复杂性,不利于自定义与调试分析,我建议是慎用。
主要的还是要把模型维护清楚
思寒大佬,我的想法是这样
- 区别于官网的描述,对于一般的元素, 使用描述器的 get 直接获取元素,而不是元素的属性或者文本,相当于一般在BasePage里面调用find_element方法直接拿到元素
比如
class BaseElement(object):
"""元素的基类"""
def __init__(self, *args):
self.locator = args
def __get__(self, instance, owner) -> WebElement:
driver = instance.driver
return WebDriverWait(driver, 10).until(
lambda d: driver.find_element(*self.locator)
)
class BasePage(object):
button = BaseElement(By.XPATH,"//button")
def __init__(self, selenium_driver):
self.driver: WebDriver = selenium_driver
这样每次调用page页面的button,只需要写这样的代码 Page(driver).button.click()
,而不是每次调用find_element这样,节省一些代码量。
- 然后对于一些特殊的元素进行扩展
例如对于一些相同组件定位相同的元素,可以使用模版的方式进行传参
class ButtonElement(BaseElement):
template = "//button[span='%s']"
def __init__(self, *args):
locator = self.template % args
super(TemplateElement, self).__init__(By.XPATH, locator)
class BasePage(object):
button = ButtonElement("查询")
def __init__(self, selenium_driver):
self.driver: WebDriver = selenium_driver
- 最后对于使用相同组件的页面,让__get__方法返回更复杂的组件类,
我的思路是先定位到组件最外层的元素,然后使用相对定位定位定位组件内部的元素,把组件的一些简单的操作封装。后面即使组件有变动,我也只需要改组件类。
这样页面类由描述器封装的 组件和元素 构成,让页面类看起来像搭积木一样组成
然后这是我基于这个思路写了个简单的demo
实现了公司的前端一些基础组件(表格,表单,树)的定位和操作。
但是在做的过程中感觉确实对于有些复杂的组件可能会定义比较复杂,代码的复用程度可能没有我预期的那么高,但是算是个实践吧,请大佬有时间指点一下思路