Appium-Python-Client 源码剖析 (一) driver 的元素查找方法

目录

前言

源码版本:0.9

结构图:

mobileby.py

[appium 的 webdriver.py](#appium 的 webdriver.py)

[selenium 的 webdriver.py](#selenium 的 webdriver.py)

seleniumdriver

appiumdriver


前言

Appium-Python-Client是一个用于Python语言的Appium客户端库,它提供了丰富的API和功能,用于编写和执行移动应用程序的自动化测试。在本文中,我们将深入剖析Appium-Python-Client的源码,重点关注driver的元素查找方法。

Appium 的实用方法都藏在 Client 的源码里,我尝试在这里剖析一下 Client 的源码,第一篇,我们直接从大家最关注的元素查找说起。

注意!对于 driver 和 webelement 实例,均有对应的元素查找方法(webelement 查找的是下面的子元素),本文讨论的元素查找针对的是 driver 实例。

源码版本:0.9

结构图:

mobileby.py

OK,现在假如我们需要自定义一些 find 方法,比如 find_element_by_xxxx,我们该怎么做?我们看到,appium 提供了一些扩展的 find 方法,它有它自己的一套方式,例如 ACCESSIBILITY_ID 等,要想自定义实现这些方法,appium 首先做的就是:自定义一个 MobileBy 类,这个类从 By 类中继承,然后添加一些需要的属性,这些属性的 value 就是一些文本,不用担心他们不起作用,假如你熟悉 webdriver 的原理,应该会更好地理解。

复制代码
#!/usr/bin/env python
from selenium.webdriver.common.by import By

class MobileBy(By): #这里显然是一个继承
    """三个扩展属性,清清楚楚地罗列在这里"""
    IOS_UIAUTOMATION = '-ios uiautomation'
    ANDROID_UIAUTOMATOR = '-android uiautomator'
    ACCESSIBILITY_ID = 'accessibility id'

既然他继承自 By 类,我们直接戳到 By 类看一下,因为 By 类中还有一个 classmethod 下面会用到:

复制代码
class By(object):
    """
    Set of supported locator strategies.
    """

    ID = "id"
    XPATH = "xpath"
    LINK_TEXT = "link text"
    PARTIAL_LINK_TEXT = "partial link text"
    NAME = "name"
    TAG_NAME = "tag name"
    CLASS_NAME = "class name"
    CSS_SELECTOR = "css selector"

    @classmethod #好吧,我是一个类方法,下文中会用到我
    def is_valid(cls, by): #cls是把类对象本身传进来
        for attr in dir(cls):
            if by == getattr(cls, attr): #判断是不是可用的查找方式
                return True
        return False

这个 MobileBy 类在哪边起作用?我们去跟踪一下,来到这里:

appium 的 webdriver.py
复制代码
def find_element_by_ios_uiautomation(self, uia_string):
    """Finds an element by uiautomation in iOS.

    :Args:
     - uia_string - The element name in the iOS UIAutomation library

    :Usage:
        driver.find_element_by_ios_uiautomation('.elements()[1].cells()[2]')
    """
    #这里直接访问Appium自己定义的几个类属性
    return self.find_element(by=By.IOS_UIAUTOMATION, value=uia_string)

def find_elements_by_ios_uiautomation(self, uia_string):
    """Finds elements by uiautomation in iOS.

    :Args:
     - uia_string - The element name in the iOS UIAutomation library

    :Usage:
        driver.find_elements_by_ios_uiautomation('.elements()[1].cells()[2]')
    """
    return self.find_elements(by=By.IOS_UIAUTOMATION, value=uia_string)

def find_element_by_android_uiautomator(self, uia_string):
    """Finds element by uiautomator in Android.

    :Args:
     - uia_string - The element name in the Android UIAutomator library

    :Usage:
        driver.find_element_by_android_uiautomator('.elements()[1].cells()[2]')
    """
    return self.find_element(by=By.ANDROID_UIAUTOMATOR, value=uia_string)

def find_elements_by_android_uiautomator(self, uia_string):
    """Finds elements by uiautomator in Android.

    :Args:
     - uia_string - The element name in the Android UIAutomator library

    :Usage:
        driver.find_elements_by_android_uiautomator('.elements()[1].cells()[2]')
    """
    return self.find_elements(by=By.ANDROID_UIAUTOMATOR, value=uia_string)

def find_element_by_accessibility_id(self, id):
    """Finds an element by accessibility id.

    :Args:
     - id - a string corresponding to a recursive element search using the
     Id/Name that the native Accessibility options utilize

    :Usage:
        driver.find_element_by_accessibility_id()
    """
    return self.find_element(by=By.ACCESSIBILITY_ID, value=id)

def find_elements_by_accessibility_id(self, id):
    """Finds elements by accessibility id.

    :Args:
     - id - a string corresponding to a recursive element search using the
     Id/Name that the native Accessibility options utilize

    :Usage:
        driver.find_elements_by_accessibility_id()
    """
    return self.find_elements(by=By.ACCESSIBILITY_ID, value=id)

所以,我们现在知道了,appium 的这些扩展方法都是通过继承 webdriver.Remote 类来直接扩展的,appium 扩展了 webdriver.Remote 来满足他的需求,我们尝试去追踪一下 find_element 和 find_elements 这两个核心方法!

selenium 的 webdriver.py

OK,我们终于来到实现的主体(核心)部分:find_element,find_elements:

复制代码
def find_element(self, by=By.ID, value=None):
        """
        'Private' method used by the find_element_by_* methods.

        :Usage:
            Use the corresponding find_element_by_* instead of this.

        :rtype: WebElement
        """
        if not By.is_valid(by) or not isinstance(value, str):
            raise InvalidSelectorException("Invalid locator values passed in")

        return self.execute(Command.FIND_ELEMENT,
                             {'using': by, 'value': value})['value']

    def find_elements(self, by=By.ID, value=None):
        """
        'Private' method used by the find_elements_by_* methods.

        :Usage:
            Use the corresponding find_elements_by_* instead of this.

        :rtype: list of WebElement
        """
        if not By.is_valid(by) or not isinstance(value, str):
            raise InvalidSelectorException("Invalid locator values passed in")

        return self.execute(Command.FIND_ELEMENTS,
                             {'using': by, 'value': value})['value']

OK,我们从头到尾再试着理一下:

appium 为了实现自己的 find 查找方式,首先自定义了一个 MobileBy 类,给这个类对象塞入了它定义的一些扩展属性,这些属性的值会通过 webdriver 协议推送到 server 端去识别和执行,为了让这些属性运用到 find 方法中,appium 很好地继承和扩展了 webdriver.Remote,然后通过调用 driver 实例的 find_element 和 find_elements 两个核心方法实现元素查找,所以,既然是扩展,appiumdriver 实例可以使用 seleniumdriver 的所有关于元素查找的实例方法,他们的列表我们就可以整理出来了

seleniumdriver

find_element_by_id

find_elements_by_id

find_element_by_name

find_elements_by_name

find_element_by_link_text

find_elements_by_link_text

find_element_by_partial_link_text

find_elements_by_partial_link_text

find_element_by_tag_name

find_elements_by_tag_name

find_element_by_xpath

find_elements_by_xpath

find_element_by_class_name

find_elements_by_class_name

find_element_by_css_selector

find_elements_by_css_selector

appiumdriver

find_element_by_ios_uiautomation

find_elements_by_ios_uiautomation

find_element_by_android_uiautomator

find_elements_by_android_uiautomator

find_element_by_accessibility_id

find_elements_by_accessibility_id

作为一位过来人也是希望大家少走一些弯路

在这里我给大家分享一些自动化测试前进之路的必须品,希望能对你带来帮助。

(软件测试相关资料,自动化测试相关资料,技术问题答疑等等)

相信能使你更好的进步!

点击下方小卡片

相关推荐
蓁蓁啊3 小时前
GIT使用SSH 多账户配置
运维·git·ssh
程序猿小三5 小时前
Linux下基于关键词文件搜索
linux·运维·服务器
虚拟指尖6 小时前
Ubuntu编译安装COLMAP【实测编译成功】
linux·运维·ubuntu
椎4957 小时前
苍穹外卖前端nginx错误之一解决
运维·前端·nginx
刘某的Cloud7 小时前
parted磁盘管理
linux·运维·系统·parted
极验7 小时前
iPhone17实体卡槽消失?eSIM 普及下的安全挑战与应对
大数据·运维·安全
爱倒腾的老唐7 小时前
24、Linux 路由管理
linux·运维·网络
yannan201903137 小时前
Docker容器
运维·docker·容器
_清浅7 小时前
计算机网络【第六章-应用层】
运维·服务器·计算机网络
书弋江山7 小时前
iOS一直讲的单元格优化
macos·ios·cocoa