一盏小灯 [Selenium UI 自动化] 如何封装一套你自己的常用自动化方法

Jerry li · 2020年05月31日 · 1904 次阅读

为什么要二次封装?

  • 对一些常用的方法进行二次封装
  • 简化用例的代码

步骤 1:driver 的初始化

  • 定义了 extend 这个 class 作为对 selenium 常用方法的二次封装
  • 初始化了类的属性 driver: 如果 driver 不存在,则通过 selenium webdriver 进行初始化; 如果已经被初始化过,则直接返回
  • 在 init driver 的方法中,可以将你常用的 webdriver 启动方式加在里面。比如使用指定的浏览器类型或 webdriver 的路径; 是否使用 headless 模式运行; 是否使用远程的 selenium server 执行; 是否需要指定为 chrome 的模拟手机功能; 是否需要默认最大化。等等。

from selenium import webdriver
class extend():
    """
    You can add new function here for you own.
    """

    def __init__(self):
        self.driver = self.init_driver()

    def init_driver(self):
        global driver
        if driver is None:
            print('======initial driver=====')
            chromeOptions = webdriver.ChromeOptions()
            chromeOptions.add_experimental_option('useAutomationExtension', False)
            driver = webdriver.Chrome(chrome_options=chromeOptions,desired_capabilities=chromeOptions.to_capabilities())
            driver.maximize_window()
        return driver

步骤 2: 封装一个自己通用的查找元素方式

在 selenium 执行 UI 自动化测试的过程中,会经常遇到以下问题:

  • 某个元素没找到导致执行失败。需要加入失败重试机制。
  • 不同的元素定位方式需要使用不同的方法。如果要换定位方式,需要修改对应的代码。

基于这些问题,我先封装一个通用的查找元素方法如下:

  • 参考 robot framework selenium library 的方式,以 locator 的方式来定位元素(格式为 attribute=value)
  • 返回一个 elements 的数组,并在其他的方法中扩展使用。
  • 增加一些扩展的查找元素方式,比如 is displayed 设置为 false, 则可以将隐藏的元素也找出来; 如果传入 text 的值,则会在元素中过滤出包含该文本的元素。等。

def find_elements(self,driver,locator,is_displayed=True,text=''):
    """
    Find elements using the given condition..

    :param driver:
    :param locator: like id=btn_search
    :param is_displayed: True : Only the elements shown on the page will be returned.    False: Elements will also be returned no matter is shown or hidden.
    :param text: Only the elements contain the specified text will be returned.
    :return: Found element list.
    """
    method, value = locator.split('=',maxsplit=1)
    if 'css' in method:
        method = By.CSS_SELECTOR
    elif 'class' in method:
        method = By.CLASS_NAME
    elif 'text' in method:
        method = By.PARTIAL_LINK_TEXT
    elif 'tag' in method:
        method = By.TAG_NAME
    elements = driver.find_elements(by=method,value=value)
    new_elements = []
    for element in elements:
        if text != '':
            if self.is_text_in_element(element,text):
                if is_displayed:
                    if element.is_displayed():
                        new_elements.append(element)
                else:
                    new_elements.append(element)
        else:
            if is_displayed:
                 if element.is_displayed():
                    new_elements.append(element)
            else:
                new_elements.append(element)
    return new_elements


def find_element(self,driver,locator,is_displayed=True,index=0,text=''):
    """
    Find element using the given condition..

    :param driver:
    :param para_list: [method, value] eg : ['id','add_btn']
    :param is_displayed: True : Only the element shown on the page will be returned.    False: Element will also be returned no matter is shown or hidden.
    :param index: If more than one element is found, driver will return the specified element by index.  e.g: element 0,1,2 is found and the index is set to by 2, the element 2 will be returned.
    :param text: Only the element contains the specified text will be returned.
    :return: Found element.
    """
    elements = self.find_elements(driver,locator,is_displayed=is_displayed,text=text)
    if len(elements)>0 and index < len(elements):
        return elements[index]
    else:
        return elements[0]


步骤 3: 扩展

扩展常用的操作步骤:

  • click: 点击元素。 如果有多个符合条件的元素,还可以指定要点击第几个。 使用例子: click_index('class=btn',index=1) # 点击第 2 个 class 为 btn 的按钮

def click_index(self,driver,locator,index=0):
    """
    When more than one web element are found by the given value, you can use the index the specified which element you want to click.

    :param driver:
    :param index: default to 0, means to click the first element found.
    :return:
    """

    elements = self.find_elements(driver, locator)
    elements[int(index)].click()
    time.sleep(2)
  • fill: 输入 例子:
    fill('id=searchField',text='testerhome')
def fill(self,driver,locator,text, is_displayed = True,index=0):
     """
     Fill specified text to the target web elelemnt.

     :param driver:
     :param para_list: [method, value]
     :param text:    the text you want to input
     :param is_displayed:
     :param index:
     :return:
     """
     text = self.replaceRandomValue(text)
     elements = self.find_elements(driver, locator,is_displayed,text='')
     elements[index].clear()
     elements[index].send_keys(text)
  • 点击文字: 例如一些通用的按钮或者菜单,可直接通过对于的文本来点击,无需关心 id、xpath 等属性。 简化用例的编写。

def click_text(self,driver,text,type=''):
    """
    click a web element by it's text and type.

    :param driver:
    :param text:
    :param type: by default is empty.  you can specified the type to it's tag name.  e.g : span, li, a .
    :return:
    """
    if len(type) ==0:
        try :
            driver.find_element_by_link_text(text).click()
        except:
            try:
                driver.find_element_by_partial_link_text(text).click()
            except:
                elements = driver.find_elements(by='xpath', value="//*[contains(.,'" + text + "')]")
                for element in elements:
                    element.click()
    else:
        elements = self.find_elements(driver, ['tag', type], is_displayed=True, text=text)
        if len(elements):
            elements[0].click()
    time.sleep(2)
  • 尝试点击某元素: 适用于某些偶然条件下出来的按钮或者窗口
def try_click(self,driver,locator):
     """
     Try to click on a specified web element.  Sometimes a message will be popped up on a web page. We need this function to close the pop up window.

     :param driver:
     :param para_list:
     :return:
     """
     for i in range(3):
         try:
             self.find_element(driver, locator).click()
             break
         except:
             pass
     time.sleep(2)
  • 滚动页面到底部; 滚动页面到某个元素 例如某个页面较长,可以通过这个方法滚动到对于的按钮后再进行操作; 甚至可以将其内置到 点击、填写等操作类方法中,解决元素不在当前可见区域时无法操作的问题。
def scroll_down(self,height=0):
    if height:
        self.driver.execute_script('window.scrollTo(0,%s)' %height)
    else:
        self.driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')

def scroll_to_element(self,locator):
    for i in range(1,50):
        height = i*200
        self.driver.execute_script('window.scrollTo(0,%s)' % height)
        self.wait(1)
        if len(self.find_elements(locator)):
            break

如何使用:

from app.core.extend import extend

new_driver = extend()  # 初始化自己封装的driver 库
new_driver.driver.get('https://www.baidu.com')   # 仍可以通过 .driver  来调用原来 selenium 的driver 方法
new_driver.fill('id=kw','testerhome')
new_driver.click_index('id=su')
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册