poium 一直我在维护的一个开源项目, 它的定位是以极简的方式在自动化项目中 Page Objects 设计模式. 我在之前的文章中也有介绍.
本篇文章主要介绍一个 JavaScript 元素操作的封装原理.
为什么要封装 JavaScript 的 API?
因为有些场景下 Selenium 提供的 API 并不能满足我们需求. 比如, 滑动浏览滚动条, 控制元素的显示 / 隐藏, 日历控件的操作等, 都可以通过 JavaScrip 实现, 而且 Selenium 为我们提供了 execute_script() 方法可以用来运行 JavaScrip 脚本.
旧的设计思路
先看旧的设计代码和调用.
- # ===== 封装代码 ======
- class Page(object):
- def __init__(self, driver):
- self.driver = driver
- def set_text(self, CSS_selector, value):
- """
- JavaScript API, Only support css positioning
- Simulates typing into the element.
- """ JS ="""var elm = document.querySelector("{css}");
- elm.style.border="2px solid red";
- elm.value = "{value}";""".format(CSS=css_selector(), value=value)
- self.driver.execute_script(JS)
- def click(self, css_selector):
- """
- JavaScript API, Only support css positioning
- Click element.
- """ JS ="""var elm = document.querySelector("{css}");
- elm.style.border="2px solid red";
- elm.click();""".format(CSS=css_selector())
- self.driver.execute_script(JS)
- class CSSElement(object):
- def __init__(self, CSS):
- self.CSS = CSS
- def __call__(self):
return self.CSS
- # ======= 调用代码 ==============
- from selenium import webdriver
- class baiduPage(Page):
- search_input = CSSElement("#kw")
- search_button = CSSElement("#su")
- dr = webdriver.Chrome()
- dr.get("http://www.baidu.com")
- page = baiduPage(dr)
- page.set_text(page.search_input, "poium")
- page.click(page.search_button)
- dr.close()
如果你看不懂上面的封装代码的话, 可以重点看下面的调用代码, 针对元素的点击和输入.
- page.set_text()
- page.click()
表示操作的方法, 在 Page 类中实现.
- page.search_input
- page.search_button
表示操作的对象, 在 Page 的继承类 baiduPage 中定义.
- page.set_text(page.search_input, "poium")
- page.click(page.search_button)
操作的动作 和 操作的对象 都是以 page. 调用, 万一我要操作的对象也命名为 click 那不就和操作的动作 傻傻分不清楚了, 所以, 这样的语法不是很怪么?
所以, 这个问题一直困扰我挺久的, 我一直没想到更好的设计.
新的设计思路
直到前几天又重新学习了 Python 的 __get__ 和 __set__ 内置方法, 才把这个问题解决.
- # ===== 封装代码 ======
- class Page(object):
- def __init__(self, driver):
- self.driver = driver
- class CSSElement(object):
- driver = None
- def __init__(self, CSS):
- self.CSS = CSS
- def __get__(self, instance, owner):
- if instance is None:
- return None
- global driver
- driver = instance.driver
- return self
- def set_text(self, value):
- global driver
- driver.execute_script("""var elm = document.querySelector("{css}");
- elm.style.border="2px solid red";
- elm.value = "{value}";""".format(CSS=self.CSS, value=value))
- def click(self):
- global driver
- driver.execute_script("""var elm = document.querySelector("{css}");
- elm.style.border="2px solid red";
- elm.click();""".format(CSS=self.CSS))
- # ======= 调用代码 ==============
- from selenium import webdriver
- class baiduPage(Page):
- search_input = CSSElement("#kw")
- search_button = CSSElement("#su")
- dr = webdriver.Chrome()
- dr.get("http://www.baidu.com")
- page = baiduPage(dr)
- page.search_input.set_text("poium")
- page.search_button.click()
- dr.close()
如果看不懂封装代码的话, 直接看调用代码.
- page.search_input.set_text("poium")
- page.search_button.click()
page 表示页面; search_input 表示页面上的某个对象; set_text() 表示对象的动作.
这样的语法是不是要比前面好了很多? 而保持了与 Selenium API 封装的语法一致性.
项目地址: https://github.com/defnngj/poium
做开源项目的生活就是这么朴实无华, 且有趣!
来源: https://www.cnblogs.com/fnng/p/11415590.html