# 可定位的控件属性
App中的属性 | 等价 Web 中的属性 | 代码表达式 | 注意点 |
---|---|---|---|
resource-id | id | driver.find_element_by_id("id") driver.findElement(By.id("id")) |
在App中,id可能不是唯一的 |
class | class/tag | driver.find_element_by_class_name("class") driver.findElement(By.className("class")) xpath: //class[id = "id"] |
1、当使用 class_name 去定位时,可以理解成类名 2、当使用xpath定位时,class就是tag(标签名),并不是类名。 |
text | name | driver.find_element_by_name("name") driver.findElement(By.name("name")) |
name是一个属性 |
content-desc | 无 | driver.find_element_by_accessibility_id("desc") | content-desc属性是用来描述该元素的作用的 |
定位入门
软件:微博国际版
import time
from appium import webdriver
desired_caps = {
"platformName": "android",
"deviceName": "bc3ef5d5",
"appPackage": "com.weico.international",
"appActivity": ".activity.MainFragmentActivity",
"noReset": True,
"newCommandTimeout": 6000
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
test = driver.find_element_by_class_name("android.widget.TextView")
print(test)
print("打印1:" + test.text)
test = driver.find_element_by_xpath("/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/androidx.drawerlayout.widget.DrawerLayout/android.view.ViewGroup/android.widget.RelativeLayout/android.widget.TabHost/android.widget.FrameLayout/android.view.ViewGroup/android.widget.FrameLayout/android.widget.FrameLayout/androidx.recyclerview.widget.RecyclerView/android.widget.LinearLayout[2]/android.widget.RelativeLayout[1]/android.widget.TextView[1]")
print("打印2:" + test.text)
test = driver.find_element_by_xpath("//*[contains(@text,'冈瓦纳')]")
print("打印3:" + test.text)
>>>
打印1:查看新微博
打印2:冈瓦纳
打印3:冈瓦纳
为什么打印1是,查看新微博?
因为多个class_name的名字是一样的,find_element_by
只返回第一个。如果要全部返回,则改成find_elements_by
匹配多个元素,再更具索引去匹配
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
test = driver.find_elements_by_class_name("android.widget.TextView")
for i in test:
print("打印1:" + i.text)
>>>
打印1:查看新微博
打印1:全部
打印1:
打印1:烫师傅
打印1:11 分钟前
打印1:iQOO 3 5G性能旗舰
...
高级元素定位方式之 UI Automator API
前面介绍过根据id,classname, accessibilityid,xpath来定位元素,其他这些方法底层都是利用了 UI Automator 的 API 功能实现的
UI Automator 介绍
- UI Automator 测试框架提供了一组 API 来构建 UI 测试,用于在用户应用和系统应用中执行交互
- 利用 UI Automator API,可以打开“设置”菜单或应用启动器等操作
- UI Automator 测试框架非常适合编写黑盒自动化测试,其中的测试代码不依赖于目标应用的内部
UI Automator 提供的功能
- 自带的元素定位工具
- 在设备上检索状态信息并执行操作的API
- 支持跨应用 UI 测试的API
UI Automator 访问设备状态
UI Automator 测试框架提供了一个 UiDevice
类,用于在 app 运行的设备上进行访问和执行等操作,它提供了以下操作
- 更改设备旋转
- 按D-pad按钮
- 按返回、主屏幕、菜单按钮
- 打开通知栏
- 对当前窗口进行屏幕截图
更多的 UI Automator API
利用 UI Automator API
,可以编写稳健可靠的测试,而无需了解目标应用的实现详情
下面将列出常见的类,它们都是在 android.support.test.uiautomator 这个库下的
类 | 类名 | 作用 |
---|---|---|
UiDevice | 设备封装类 | 上面说到的,获取设备信息和设备交互 |
UiObject | 所有空间抽象类 | 表示设备上可见的一个Android控件 |
UiSelector | 控制选择器 | 在设备上查询一个或多个目标 UI 元素 |
Configurator | 配置基类 | 设置运行 UI Automator 测试所需的关键参数 |
UiScrollable | 滚动控件 | 当目标控件存在于屏幕之外时使用 |
UiCollection | 控件集合 | 控件遍历,枚举容器的 UI 元素以便计算子元素个数 |
- 其中
UiSelector
在 appium 自动化代码选择元素时候直接使用到的 - 用来生成一个定位器来选择界面中的控件元素,可以通过text,content-desc,class,和一些状态信息来进行条件过滤
UiSelector
类似于 appium中find_element_by_xxx()
方法中函数值- UiSelector官方文档:https://developer.android.google.cn/reference/android/support/test/uiautomator/UiSelector
UiSelector 初体验
java语法
new UiSelector().resourceId(“io.manong.developerdaily:id/tv_tab_title”)
结合 Appium 的用法
driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.hpbr.bosszhipin:id/tv_tab_label")')
# 此处省略配置代码...
# 通过resourceId
test = driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.hpbr.bosszhipin:id/tv_tab_label")')
print(test.text)
# 通过text
test = driver.find_element_by_android_uiautomator('new UiSelector().text("附近")')
print(test.text)
# 通过className
test = driver.find_element_by_android_uiautomator('new UiSelector().className("android.widget.TextView")')
print(test.text)
UiSelector 还可以通过哪些方法来定位元素
方法名 | 作用 |
---|---|
className(String className) | 根据class名称 |
classNameMatches(String regex) | 根据class名称的正则表达式 |
description(String desc) | 根据content-desc |
descriptionContains(String desc) | 根据content-desc中包含的字符串 |
text(String text) | 根据文本值text |
textContains(String text) | 根据文本值text包含的字符串 |
resourceId(String id) | 根据resource-id |
基本上除了xpath之外,可以通过appium实现的元素定位方式,UIAutomator也有,因为底层就是靠他实现的
xpath 虽然没有直接对应的方法,但是像下面这种 xpath 写法,UIAutomator 也有对应的方法
- // :表示任意后代关系
- x[n] : 表示第几个子节点
方法名 | 对应xpath的语法 | 作用 |
---|---|---|
childSelector(UiSelector selector) | // | 用来选择后代元素(可以是非直接子元素),对应// |
index(int index) | *[n] | index表示其父元素下的第几个节点 |
instance(int instance) | 无 | 匹配的结果所有元素里面的第几个元素 比如通过 // android.widget.TextView 找到了十个对应类型的元素,instance(1) 表示第二个对应的元素,下标是从0开始的 |
# 正常appium写法
test = driver.find_elements_by_id("com.hpbr.bosszhipin:id/tv_tab_label")[1]
# 结合uiautomator写法
test = driver.find_element_by_android_uiautomator('new UiSelector().resourceId("com.hpbr.bosszhipin:id/tv_tab_label").enabled(true).instance(1)')