说明
selenium升级至4.0后就不再支持find_element_by*方法,居于此的appium-python-client也不再支持此类方法。现在appium支持find_element(by, value)以及find_elements(by, value)这两种方法,by的值主要有以下两类:
- 第一类是继承selenium中的by值,by值有以下几种:
class By:
"""
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"
- 第二类是appium封装的其他库的接口,比如UIautomator2,by值有以下几种:
from selenium.webdriver.common.by import By
class AppiumBy(By):
IOS_PREDICATE = '-ios predicate string'
IOS_UIAUTOMATION = '-ios uiautomation'
IOS_CLASS_CHAIN = '-ios class chain'
ANDROID_UIAUTOMATOR = '-android uiautomator'
ANDROID_VIEWTAG = '-android viewtag'
ANDROID_DATA_MATCHER = '-android datamatcher'
ANDROID_VIEW_MATCHER = '-android viewmatcher'
# Deprecated
WINDOWS_UI_AUTOMATION = '-windows uiautomation'
ACCESSIBILITY_ID = 'accessibility id'
IMAGE = '-image'
CUSTOM = '-custom'
第一类用来定位元素的方法底层都是利用了UI Automator的API实现的,我在实际搭建测试框架中发现直接使用UI Automator封装的方法定位元素,速度更快也更准确,所以这里主要介绍一下Android UI Automator定位元素的方法;
介绍
它是Android自带的元素定位工具,在设备上检索状态信息并执行操作的API,也支持跨应用UI测试的API,以下为UI Automator API常见的类,这些类都在Android.support.test.uiautomator这个库下:
类 | 类名 | 作用 |
---|---|---|
UiDevice | 设备封装类 | 获取设备信息和设备交互 |
UiObject | 所有空间抽象类 | 表示设备上一个可见的Android控件 |
UiSelector | 控制选择器 | 在设备上查询一个或多个目标UI元素 |
Configurator | 配置基类 | 设置运行UI Automator测试所需的关键参数 |
UiScrollable | 滚动控件 | 当目标控件存在于屏幕之外使用 |
UiCollection | 控件集合 | 控件遍历,枚举容器的UI元素以便计算子元素个数 |
- UiSelector在appium自动化定位元素中直接使用:
driver.find_element('-android uiautomator','new UiSelector().text("全部")').click()
关于UiSelector中文文档:https://www.apiref.com/android-zh/android/support/test/uiautomator/UiSelector.html
我常用的用以定位元素的方法:
方法 | 作用 |
---|---|
text | 根据文本值text |
className | 根据class名称 |
description | 根据content-desc |
resourceId | 根据resourceId |
textContains | 根据文本值text包含的字符串 |
其中也有根据索引来定位元素的方法,包括instance和index
方法 | 语法 | 作用 |
---|---|---|
index | *[n] /.index(n) | 通过该控件所在层级的节点将对应的控件取出来 ,匹配的是父元素下的第几个节点 |
instance | .instance(n) | 会将界面上所有相同类型的控件按顺序取出来,然后再按照控件在这个里面的顺序把它取出来 |
和显示等待机制WebDiverWait一起使用
与隐式等待不同,显示等待时针对单个元素进行定位等待的,一般定位控件就是要对它进行操作,但是控件的加载需要时间,如果超过规定时间仍未定位到元素,就定位元素失败,抛出异常;
fromselenium.webdriver.support.ui importWebDriverWait
WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
参数说明:
driver:返回的driver对象
timeout:最长等待时间,如果使用了隐式等待的话,这里也要考虑隐式等待的时间
poll_frequency:检查元素的时间间隔,默认是0.5s,即为每隔0.5s查找一次
ignored_exceptions:超时后抛出的异常信息,默认是NoSuchElementExeception
WebDiverWait()与unit和unit_not方法结合使用
until/until_not(method, message=‘’)
调用driver提供的方法作为参数,直到返回值为false
这里需要结合两个类:
expected_condition类:其中有比较多的预期条件判断的方法,一般比较常用的有前三种方法:
方法 | 说明 |
---|---|
presence_of_element_located | 判断某个元素是否被加载到dom树里,但该元素不一定可见 |
visibility_of_element_located | 判断某个元素是否可见,可见元素非隐藏,并且元素宽和高都不等于0 |
element_to_be_clickable | 判断某个元素中是否可见并且可点击 |
title_is | 判断当前页面的title是否完全等于==预期字符串,返回布尔值 |
title_contains | 判断当前页面的title是否包含预期字符串,返回布尔值 |
visibility_of | 与visibility_of_element_located相同,只是这一方法的参数是定位后的元素,上一方法参数是locator |
presence_of_all_elements_located | 判断是否至少有一个元素存在于dom树中 |
text_to_be_present_in_element | 判断某个元素的text是否包含了预期的字符串 |
text_to_be_present_in_element_value | 判断某个元素的value属性是否包含了预期的字符串 |
frame_to_be_avaliable_and_switch_to_it | 判断该frame是否可以switch进去,如果可以的话,返回True并且switch进去,否则返回false |
invisibility_of_element_located | 判断某个元素是否不存在于dom树或不可见 |
element_to_be_clicked | 判断某个元素是否可见并且可点击 |
staleness_of | 等某个元素从dom树中移除,注意,这个方法也是返回true或者false |
element_to_be_selected | 判断某个元素是否被选中,一般用在下拉列表 |
element_selection_state_to_be | 判断某个元素的选中状态是否符合预期 |
element_located_selection_state_to_be | 跟上一方法一样,只是这一方法传入locator,上一方法传入定位到的element |
alert_is_present | 判断页面是否存在alert |
也可以自定义等待条件;
by:支持定位元素的类,所支持的定位元素的分类见文章开头;
结合以上,重新封装元素定位的类,排除非bug因素导致的脚本运行失败
例如:
隐式等待
implicitlywait():隐式等待是由webdriver提供的超时等待方法,与sleep相比,sleep只能在一个固定时间内等待,而隐式等待可以在一个时间范围内等待,成为隐式等待;
- 脚本执行到某个元素定位时,如果元素可以定位,则继续执行,如果元素定位不到,将以轮询的方式不断判断元素是否被定位到,假设在规定时间内定位到了元素则继续执行,若规定时间过后,还没有定位到元素,则会抛出异常;
- 一旦设置了隐式等待,则会存在于整个webdriver对象实例的声明周期中,隐式的等待会让一个正常响应的应用测试变慢;
- 它会在寻找每个元素的时候都进行等待,这样会增加整个测试的执行时间;
driver.implicity_wait(20)
#全局元素在查找时都会增加20s的等待时间