1. 程式人生 > >poium測試庫之JavaScript API封裝原理

poium測試庫之JavaScript API封裝原理

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

做開源專案的生活就是這麼樸實無華,且有趣