【L1.第六章】Appium 如何定位与页面等待实战

Python+Appium+Pytest 自动化测试教程

1、App 自动化应用控制

1.1、启动

启动应用主要有两种方式:

  1. 正常启动应用。
  2. 在脚本中启动其他应用

正常启动应用:创建一个 WebDriver 实例,用于与 Appium 服务器建立连接,并传递所需的启动配置(Desired Capabilities)。主要需要以下两个参数:

  • url:指定 Appium 服务器的 URL 地址。这通常是 Appium

    服务器的主机名和端口号,例如http://localhost:4723

  • capability:一个字典对象,包含了启动应用程序时的配置信息。这些配置信息可以包括设备名称、平台版本、应用程序包名、活动名称、自动化测试引擎、设备连接信息等。

通过将 URL 和 Capabilities 传递给启动方法,Appium 客户端库将与 Appium 服务器建立连接,并使用提供的配置信息启动相应的会话。这将创建一个可以用于与应用程序进行交互的 WebDriver 实例。
在脚本中启动其他应用:可以在设备上激活给定的应用程序,传入的 app_id 为指定应用的包名。

python 复制代码
# 启动应用:
appium_server_url = 'http://localhost:4723'
driver = webdriver.Remote(appium_server_url,options=UiAutomator2Options().load_capabilities(caps))

# 在脚本中启动其他应用:
driver.activate_app("com.xx.xx")

1.2、关闭

  1. 关闭指定 app:关闭当前操作的 app,不会关闭驱动对象
  2. 关闭驱动对象:关闭当前所有的关联的 app,并关闭驱动对象
python 复制代码
# 关闭指定 app
driver.terminate_app("com.xx.xx")
# 关闭当前所有的关联的 app,并关闭驱动对象
driver.quit()

2、常见控件定位方法

2.1、控件定位方式

在 Appium 中,控件定位是指通过一些标志性的特征来定位应用界面中的元素,以便进行自动化测试操作。Appium 支持多种控件定位方式,以下是一些常见的方法。

定位策略 描述
Accessibility ID 识别一个唯一的 UI 元素,对于 XCUITest 引擎,它对应的的属性名是 accessibility-id,对于 Android 系统的页面元素,对应的属性名是 content-desc
Class name 对于 iOS 系统,它的 class 属性对应的属性值会以XCUIElementType开头,对于 Android 系统,它对应的是 UIAutomator2 的 class 属性(e.g.: android.widget.TextView)
ID 原生元素的标识符,Android 系统对应的属性名为resource-id,iOS 为name
Name 元素的名称
XPath 使用 XPath 表达式查找页面所对应的 xml 的路径

2.2、控件查找方法 find_elements & find_element

  • 返回单个元素 WebElement
  • 返回元素列表 [WebElement, WebElement, WebElement...]
python 复制代码
# 返回单个元素 WebElement
driver.find_element(AppiumBy.xxx, "xxx属性值")
# 返回元素列表 [WebElement, WebElement, WebElement...]
driver.find_elements(AppiumBy.xxx, "xxx属性值")

# find_elements & find_element 一个有s

2.3、常用定位方式

ID 定位

  • 通过身份标识 id 查找元素
  • 写法:find_element(AppiumBy.ID, "ID属性值")

ACCESSIBILITY_ID 定位

  • 通过 accessibility id 查找元素
  • 写法:find_element(AppiumBy.ACCESSIBILITY_ID, "ACCESSIBILITY_ID属性值")

XPath 定位

  • 单属性定位://*[@属性名='属性值']
  • 多属性定位://*[@属性名='属性值' and @属性名='属性值' ]
表达式 描述
/
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置(取子孙节点)。
. 选取当前节点。
... 选取当前节点的父节点。
@ 选取属性。

演示代码

python 复制代码
from appium import webdriver
 
# 设置 Desired Capabilities
desired_caps = {
    'platformName': 'Android',
    'deviceName': 'My Device',
    'appPackage': 'com.example.app',
    'appActivity': '.MainActivity'
}
 
# 初始化 WebDriver
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
 
# 通过 Accessibility ID 定位
element = driver.find_element_by_accessibility_id('someAccessibilityID')
 
# 通过 Class Name 定位
element = driver.find_element_by_class_name('android.widget.TextView')
 
# 通过 ID 定位
element = driver.find_element_by_id('someID')
 
# 通过 Name 定位
element = driver.find_element_by_name('someName')
 
# 通过 XPath 定位
element = driver.find_element_by_xpath('//android.widget.TextView[@text="Example Text"]')
 
# 与元素交互,例如点击
element.click()
 
# 关闭 WebDriver
driver.quit()

3、 强制等待与隐式等待

3.1、强制等待

解决方案:在报错的元素操作之前添加等待。

原理:线程休眠一定时间。

python 复制代码
# 导入包
import time

time.sleep(3)  # 等待3秒

3.2、隐式等待

问题:难以确定元素加载的具体等待时间。
解决方案:针对于寻找元素的这个动作,使用隐式等待添加配置。

原理:隐式等待是一种全局的等待方式,设置一个等待时间,轮询查找(默认 0.5 秒)元素是否出现,如果没出现就抛出异常。

python 复制代码
#设置一个等待时间,轮询查找(默认0.5秒)元素是否出现,如果没出现就抛出异常
driver.implicitly_wait(3)  # 等待3秒

隐式等待无法解决的问题

元素可以找到,使用点击等操作,出现报错。

原因:

  • 页面元素加载是异步加载过程,通常 xml 会先加载完成,相应的元素属性后加载。
  • 元素存在与否是由 xml 决定,元素的交互是由属性决定。
  • 隐式等待只关注元素能不能找到,不关注元素能否点击或者进行其他的交互。

解决方案:使用显式等待。

3.3、显式等待

示例: WebDriverWait(driver实例, 最长等待时间, 轮询时间).until(结束条件)。
原理:在最长等待时间内,轮询,是否满足结束条件。

python 复制代码
# 导入需要的包
import time
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait


class TestWait:

    def setup_class(self):
        '''
        完成 capability 设置
        初始化 driver
        :return:
        '''
        # 设置 cpability
        caps = {
            # 设置 app 安装的平台(Android,iOS)
            "platformName": "Android",
            # 设置 appium 驱动
            "appium:automationName": "uiautomator2",
            # 设置设备名称
            "appium:deviceName": "遥遥领先",
            # 设置被测 app 的包名
            "appium:appPackage": "com.android.system",
            # 设置被测 app 启动页面的 Activity
            "appium:appActivity": ".ApiDxxsx"
        }

        # 初始化 driver
        self.driver = webdriver.Remote(
            "http://127.0.0.1:4723",
            options=UiAutomator2Options().load_capabilities(caps)
        )
        # 设置全局隐式等待
        self.driver.implicitly_wait(5)

    def teardown_class(self):
        '''
        关闭 driver
        :return:
        '''
        self.driver.quit()

    def test_wait(self):
        '''
        点击 OS 按钮后等待 3 秒
        显示等待 Morse Code 元素可点击
        输入框输入内容后等待 2 秒
        点击返回按钮后等待 2 秒
        :return:
        '''
        # 测试步骤
        # 找到 OS 元素
        el1 = self.driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value="OS")
        # 点击 OS 元素
        el1.click()
        # 等待 3 秒
        time.sleep(3)
        # 显示等待 Morse Code 元素可点击
        el2 = WebDriverWait(self.driver, 10).until(
            expected_conditions.element_to_be_clickable(
                (AppiumBy.ACCESSIBILITY_ID, "Morse Code")
            )
        )
        # 找到 Morse Code 元素
        el2.click()
        # 等待 3 秒
        time.sleep(3)
        # 找到输入框元素
        el3 = self.driver.find_element(AppiumBy.ID, "io.appium.android.apis:id/text")
        # 在输入框中输入内容
        el3.send_keys("ceshiren.com")
        # 等待 2 秒
        time.sleep(2)
        # 点击返回按钮
        self.driver.back()
        # 等待 2 秒
        time.sleep(2)
        # 点击返回按钮
        self.driver.back()
        # 断言:判断首页中第一个元素的文本内容是 Access'ibility
        result = self.driver.find_element(
            AppiumBy.XPATH,
            "//*[@resource-id='android:id/text1'][1]"
        )
        print(result.text)
        assert result.text == "Access'ibility"
相关推荐
源码_V_saaskw9 天前
宇鹿家政服务系统小程序ThinkPHP+UniApp
微信小程序·小程序·uni-app·微信公众平台
李少兄9 天前
解决OSS存储桶未创建导致的XML错误
xml·开发语言·python
就叫飞六吧9 天前
基于keepalived、vip实现高可用nginx (centos)
python·nginx·centos
Vertira9 天前
PyTorch中的permute, transpose, view, reshape和flatten函数详解(已解决)
人工智能·pytorch·python
神即道 道法自然 如来9 天前
如何填写“appium inspector”内容?
appium
学Linux的语莫9 天前
python基础语法
开发语言·python
程序员的世界你不懂9 天前
Appium+python自动化(三十)yaml配置数据隔离
运维·appium·自动化
匿名的魔术师9 天前
实验问题记录:PyTorch Tensor 也会出现 a = b 赋值后,修改 a 会影响 b 的情况
人工智能·pytorch·python
Ven%9 天前
PyTorch 张量(Tensors)全面指南:从基础到实战
人工智能·pytorch·python
mahuifa9 天前
PySide环境配置及工具使用
python·qt·环境配置·开发经验·pyside