Appium: 手机应用自动化测试(二)

前言

上一篇文章地址:

Appium: 手机应用自动化测试(一)-CSDN博客

下一篇文章地址:

暂无

一、元素定位

通过上一节,我们了解到可以通过adb获取当前界面的元素信息,获取如下:

This XML file does not appear to have any style information associated with it. The document tree is shown below.
<hierarchy rotation="3">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="com.coolkit:id/action_bar_root" class="android.widget.LinearLayout" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="android:id/content" class="android.widget.FrameLayout" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,160]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,48][900,160]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,48][398,160]">
<node NAF="true" index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,56][117,152]">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[54,80][102,128]"/>
</node>
<node index="1" text="我的设备25804c" resource-id="" class="android.widget.TextView" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[135,79][398,128]"/>
</node>
<node index="1" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[112,48][788,160]"/>
<node index="2" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[704,48][900,160]">
<node NAF="true" index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[704,80][772,128]">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[714,80][762,128]"/>
</node>
<node NAF="true" index="1" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[772,80][840,128]">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[782,80][830,128]"/>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,160][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,160][900,1600]">
<node index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,160][900,1426]">
<node NAF="true" index="0" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[300,527][600,1059]">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[300,599][600,1059]"/>
</node>
</node>
<node index="1" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,1450][300,1576]">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[114,1450][186,1522]"/>
<node index="1" text="定时" resource-id="" class="android.widget.TextView" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[124,1540][176,1576]"/>
</node>
<node index="2" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[300,1450][600,1576]">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[414,1450][486,1522]"/>
<node index="1" text="延时" resource-id="" class="android.widget.TextView" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[424,1540][476,1576]"/>
</node>
<node index="3" text="" resource-id="" class="android.view.ViewGroup" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[600,1450][900,1576]">
<node index="0" text="" resource-id="" class="android.widget.ImageView" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[714,1450][786,1522]"/>
<node index="1" text="循环定时" resource-id="" class="android.widget.TextView" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[698,1540][802,1576]"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
<node index="1" text="" resource-id="" class="android.widget.FrameLayout" package="com.coolkit" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][900,1600]"/>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</node>
</hierarchy>

我们将以该信息为例以及而外补充的元素信息来查看定位元素的方式。

假设 driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)

1、通过 resource-id 定位

对应的查找方法为 

driver.find_element_by_id(【元素resource-id】)
driver.find_element(By.ID, 【元素resource-id】)

通常是唯一的。

在 Android 开发和自动化测试中,resource-id 是用于唯一标识 UI 元素的一个属性。每个 UI 元素都有一个资源 ID,这个资源 ID 是在应用程序的 XML 布局文件中定义的,并且是唯一的。resource-id 可以帮助开发人员和自动化测试脚本精确地定位和操作应用中的特定元素。

2、通过 class 来定位

对应的查找方法为 

driver.find_elements_by_class_name(【元素class】)
driver.find_element(By.CLASS_NAME, 【元素class】)

通常会找到多个元素,返回列表对象,此时可以通过列表取值方式取值。

在 Android 开发和自动化测试中,class 是一个属性,用于描述 UI 元素的类型。这个属性通常会包含一个字符串值,表示元素的具体类别,如 Button, TextView, ImageView, LinearLayout 等。通过这个属性,开发人员和自动化测试工具可以更好地理解和操作不同类型的 UI 元素。

3、通过 content-desc 定位

对应的查找方法为 

driver.find_element_by_accessibility_id(【元素content-desc】)
driver.find_element(By.ACCESSIBILITY_ID, 【元素content-desc】)

content-desc 属性的主要目的是提高应用的无障碍访问性。屏幕阅读器(如 TalkBack)会读取该描述,从而帮助视障用户理解该 UI 元素的功能和内容。比如,一个按钮可能没有显示文本,但可以通过 content-desc 属性提供描述。

4、通过 xpath 定位

对应的查找方法为 

driver.find_element_by_xpath(【元素xpath】)
driver.find_element(By.XPATH, 【元素xpath】)

这个在元素描述时没有明确的属性来指定,需要学习一些xpath语法。

(1) //android.widget.TextView[@text='定时'] 

假设有个xpath为 //android.widget.TextView[@text='定时'] , 解释这个语法的各个部分如下:

//  双斜杠表示从当前节点选择文档中的所有符合条件的节点,不论它们在文档中的位置。这意味着会搜索整个文档(或 DOM 树),找到所有匹配的元素。

android.widget.TextView  这是要查找的元素类型。在 Android 中,它是一个常见的 UI 元素,用于显示文本内容。

 [@text='定时'] 方括号内的内容是条件,用于过滤前面选择的元素。@text='定时' 表示只选择那些 text 属性等于 '定时'android.widget.TextView 元素。

综合起来,//android.widget.TextView[@text='定时'] 表示查找所有 text 属性等于 '定时'android.widget.TextView 元素,不论它们在文档中的位置。

(2)//android.widget.Button[contains(@text, '延时')]

解释这个语法的各个部分如下,重复不解释:

android.widget.Button  这是要查找的元素类型。在 Android 中,它是一个常见的 UI 元素,用于表示按钮。

contains(@text, '延时')  contains 是一个函数,用于检查属性值是否包含特定的子字符串。@text 是要检查的属性,'延时' 是要查找的子字符串。这表示查找所有 text 属性包含 '延时' 字符串的 android.widget.Button 元素。

综合起来,//android.widget.Button[contains(@text, '延时')] 表示查找所有 text 属性包含 '延时' 字符串的 android.widget.Button 元素,不论它们在文档中的位置。

(3)//*[@class='android.widget.Button' and @text='循环定时']

解释这个语法的各个部分如下,重复不解释:

//*  双斜杠 // 表示从当前节点选择文档中的所有符合条件的节点,不论它们在文档中的位置。这意味着会搜索整个文档(或 DOM 树),找到所有匹配的元素。星号 * 表示选择所有元素。

[@class='android.widget.Button']  方括号 [] 用于指定条件。@class='android.widget.Button' 表示筛选 class 属性值等于 android.widget.Button 的元素。这是一个属性筛选条件,用来匹配特定类型的 UI 元素。

and  and 是一个逻辑运算符,用于连接多个条件。这里表示需要同时满足 @class='android.widget.Button'@text='循环定时' 两个条件。

[@text='循环定时']   这是第二个属性筛选条件。@text='循环定时' 表示筛选 text 属性值等于 循环定时 的元素。

综合起来 , //*[@class='android.widget.Button' and @text='循环定时'] 表示查找所有 class 属性值为 android.widget.Buttontext 属性值为 循环定时 的元素,不论它们在文档中的位置。

(4)绝对路径

//android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.widget.RelativeLayout[1]/android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]/android.widget.RelativeLayout[1]/android.widget.Button[2]

解释这个语法的各个部分如下,重复不解释:

android.widget.FrameLayout[1]android.widget.FrameLayout 表示一个 FrameLayout 类型的节点。[1] 表示选择这个类型的第一个子节点。数字从 1 开始计数,而不是 0。

/:单斜杠表示从当前节点选择直接子节点。

节点路径:这一长串路径 //android.widget.FrameLayout[1]/android.widget.FrameLayout[1]/... 表示在文档结构中嵌套的层次结构。这种路径表达式从根节点开始,逐层深入,直到定位到最终的目标元素。

android.widget.Button[2]android.widget.Button 表示一个 Button 类型的节点。[2] 表示选择这个类型的第二个子节点。

综合起来 ,从根节点开始,找到第一个 FrameLayout 类型的节点。在这个节点的子节点中,找到第一个 FrameLayout 类型的节点。依次重复这个过程,直到到达嵌套结构的末尾。最后,找到 RelativeLayout 下的第二个 Button 类型的节点。

5、通过 text 来定位

对应的查找方法为  

driver.find_element_by_android_uiautomator('new UiSelector().text("【元素text】")')
element = driver.find_element(MobileBy.ANDROID_UIAUTOMATOR,'new UiSelector().text("【元素text】")')

假设有一元素'new UiSelector().text("定时")' ,这是一种使用 Appium 和 UIAutomator 来定位 Android 应用中的元素的方法。这个语法是java语法嵌套于python中,它使用了 UIAutomator 框架中的 UiSelector 类来创建一个选择器,来查找文本内容为“定时”的元素。以下是对这个语法的详细解释:

new UiSelector():UiSelector 是 UIAutomator 提供的一个类,用于构建查找 UI 元素的选择器。new UiSelector() 创建了一个新的选择器实例。

.text("定时"):.text("定时") 是选择器的方法之一,用于查找文本内容等于“定时”的元素。当这个方法被调用时,选择器会匹配所有文本内容为“定时”的 UI 元素。

这里涉及到一个 UiSelector 类,方法小结如下:

1. text(String text)
用于根据精确文本内容定位控件。new UiSelector().text("Submit")
此代码定位文本内容为“Submit”的控件。2. textContains(String text)
用于根据部分文本内容定位控件。new UiSelector().textContains("Sub")
此代码定位包含“Sub”文本的控件,例如“Submit”或“Subscription”。3. textStartsWith(String text)
用于根据文本开头部分定位控件。new UiSelector().textStartsWith("Sub")
此代码定位文本以“Sub”开头的控件,例如“Submit”或“Subscribe”。4. textMatches(String regex)
用于根据正则表达式匹配文本内容定位控件。new UiSelector().textMatches("^Sub.*")
此代码定位文本以“Sub”开头的控件,正则表达式可以更复杂以匹配不同的文本模式。5. resourceId(String resourceId)
用于根据控件的资源 ID 进行定位。new UiSelector().resourceId("com.example:id/button")
此代码定位资源 ID 为 com.example:id/button 的控件。6. resourceIdMatches(String regex)
用于根据正则表达式匹配资源 ID 定位控件。new UiSelector().resourceIdMatches("com\\.example:.*")
此代码定位资源 ID 符合正则表达式 com.example: 开头的控件。7. className(String className)
用于根据控件的类名进行定位。new UiSelector().className("android.widget.Button")
此代码定位类名为 android.widget.Button 的控件。8. classNameMatches(String regex)
用于根据正则表达式匹配控件的类名进行定位。new UiSelector().classNameMatches("android\\.widget\\..*")
此代码定位类名以 android.widget. 开头的控件。9、组合使用示例
假设你需要定位一个按钮,它的文本以“Sub”开头,资源 ID 包含“button”,且类名为 android.widget.Button。你可以组合使用这些方法:new UiSelector().textStartsWith("Sub").resourceIdContains("button").className("android.widget.Button");
或者如果需要使用正则表达式:new UiSelector().textMatches("^Sub.*").resourceIdMatches(".*button.*").classNameMatches("android\\.widget\\.Button");
这些组合可以帮助你更加精确地定位界面上的控件。通过组合多个 UiSelector 方法,可以缩小查找范围,提高定位的准确性。

二、查看安卓手机元素的工具

1、UI Automator Viewer

UI Automator Viewer 是 Android SDK 提供的工具,用于查看 Android 应用程序的 UI 层次结构和元素属性。

2、Appium Inspector

Appium Inspector 是 Appium 提供的一个图形化界面工具,用于查看和检查应用程序的 UI 元素。

3、ADB (Android Debug Bridge)

ADB 是一个命令行工具,用于与 Android 设备进行通信。可以通过 ADB 命令获取应用的 UI 层次结构和元素属性。

4、 Espresso Test Recorder

Espresso Test Recorder 是 Android Studio 提供的工具,用于记录和生成 Espresso 测试代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/51760.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

差速解算程序,基于C++语言

下面是一个简单的 C 程序示例&#xff0c;用于计算两轮差速机器人的运动学解算。这个程序包括了运动学正解和逆解的实现。 我们将定义一个类 DiffDriveSolver&#xff0c;其中包含了正解和逆解的函数。此外&#xff0c;我们还将定义一个简单的测试函数来演示如何使用这个类。 …

Fusion360点击登录后没有跳转至浏览器

今日Fusion360崩溃后重启程序&#xff0c;点击“登录”之后没有跳转到浏览器登陆界面。搜了一下找到解决方案&#xff1a; 访问 http://login.autodesk360.com/ 并登录Autodesk账号。重新启动Fusion 360.

软件测试必备 - 14个接口与自动化测试练习网站

随着互联网和移动应用的快速发展,接口和自动化测试的重要性日益凸显。越来越多的企业开始重视API测试,因为它不仅能提升开发效率,还能确保系统的稳定性和安全性。这些练习网站为测试人员提供了宝贵的资源,帮助他们掌握必要的技能,应对日益复杂的测试需求。 在软件测试的世…

如何将远程修改同步到个人fork仓库

1、添加 远程上游仓库 // git remote add <remote-name> <url> git remote add upstream https://github.com/Soft/someproject.git //远程主干仓库 git remote add origin https://github.com/Demodevelop/someproject.git //远程仓库的fork 仓库 需要将远程…

【Linux】TCP全解析:构建可靠的网络通信桥梁

文章目录 前言1. TCP 协议概述2. TCP报头结构3. 如何理解封装和解包呢&#xff1f;4. TCP的可靠性机制4.1 TCP的确认应答机制 4.2 超时重传机制5. TCP链接管理机制5.1 经典面试题&#xff1a;为什么建立连接是三次握手&#xff1f;5.2 经典面试题&#xff1a;为什么要进行四次挥…

第10章、dva介绍与环境搭建;

一、介绍与环境搭建; 1、介绍; dva 首先是一个基于 redux 和 redux-saga 的数据流方案,然后为了简化开发体验,dva 还额外内置了 react-router 和 fetch,所以也可以理解为一个轻量级的应用框架。 2、特性; 易学易用:仅有 6 个API,对 redux 用户尤其友好,配合 umi 使用…

探索 Laravel 事件工厂:构建测试数据的高效工具

探索 Laravel 事件工厂&#xff1a;构建测试数据的高效工具 引言 Laravel&#xff0c;作为一个优雅而强大的PHP框架&#xff0c;提供了许多令人惊叹的功能来简化开发过程。其中&#xff0c;事件工厂&#xff08;Event Factories&#xff09;是Laravel测试工具箱中一个非常有用…

Java每日一题 ~ 盛最多水的容器

. - 力扣&#xff08;LeetCode&#xff09; 1.题目解析 本题的要求就是&#xff1a;给定数组索引之间的差值为宽&#xff0c;元素值中小的为边长求面积。 2.算法分析 思路一&#xff1a;暴力枚举 暴力法的思路是对所有可能的容器组合进行穷举&#xff0c;计算它们能容纳的水…

[硬件]—电感传感器

电感传感器 1.概述 工作基础&#xff1a;电磁感应&#xff0c;即利用线圈自感或互感的改变来实现非电量测量。工作原理&#xff1a; 被测物理量&#xff08;非电量&#xff1a;位移、振动、流量&#xff09;&#xff1b;线圈自感系数L/互感系数M&#xff1b;电压或电流&#…

自定义Laravel Artisan风格:打造个性化命令行体验

自定义Laravel Artisan风格&#xff1a;打造个性化命令行体验 引言 Laravel的Artisan命令行工具是开发过程中不可或缺的一部分&#xff0c;它提供了一个强大的接口来执行各种开发、维护、测试等任务。除了执行命令&#xff0c;Artisan还允许开发者自定义命令行输出的风格&…

设计模式实战:订单处理系统的设计与实现

问题描述 设计一个订单处理系统,支持订单的创建、处理、取消和通知功能。系统需要确保订单处理流程的灵活性和可扩展性。 设计分析 命令模式 命令模式用于将请求封装成对象,从而使我们可以用不同的请求、队列或日志来参数化其他对象。订单处理系统中的每个操作(创建订单…

0729作业+梳理

一、作业 1.写一个日志文件&#xff0c;将程序启动后的每一秒时间写入到文件中 代码&#xff1a; #include<myhead.h> #include<time.h> //判断原本文件中的行数 int len_txt(FILE *fp) { char buf0; int count 1; while(1) { buffgetc…

计算是守恒与对称的,谋算(算计)是变通与破缺的

计算通常涉及到严格的数学或逻辑规则&#xff0c;这些规则保证了信息或量的守恒和对称性。例如&#xff0c;数学运算如加减乘除都遵循特定的规律&#xff0c;确保了结果的准确性和一致性。相比之下&#xff0c;谋算&#xff08;或称算计&#xff09;更多指策略性的考虑或具有权…

Redis 缓存中间件

目录 概念 安装redis redis基本命令 给redis添加密码 基础数据类型 string类型 list列表类型 set创建&#xff08;一个键对应一个值&#xff09; set 创建数据 get 获取数据 keys * 展示所有的键 exists 判断键值是否存在 type 查看数据的类型 del 删除键 rename…

学习008-02-04-03 Group List View Data(组列表查看数据)

Group List View Data&#xff08;组列表查看数据&#xff09; This lesson explains how to group the Employee List View data by department and position. 本课介绍如何按部门和职位对员工列表视图数据进行分组。 Note Before you proceed, take a moment to review the …

机械学习—零基础学习日志(高数15——函数极限性质)

零基础为了学人工智能&#xff0c;真的开始复习高数 这里我们将会学习函数极限的性质。 唯一性 来一个练习题&#xff1a; 再来一个练习&#xff1a; 这里我问了一下ChatGPT&#xff0c;如果一个值两侧分别趋近于正无穷&#xff0c;以及负无穷。理论上这个极限值应该说是不存…

2024下《系统架构设计师》案例简答题,刷这些就够了!

2024年软考下半年已经越来越近了&#xff0c;不知道今年备考架构的同学们准备得怎么样了呢&#xff1f; 简答题一直是架构拿分的重点区域&#xff0c;对于许多考生来说&#xff0c;也往往是最具挑战性的部分。今天我就把那些重要的案例简答题类型整理汇总给大家&#xff0c;希望…

02 Go语言操作MySQL基础教程_20240729 课程笔记

概述 如果您没有Golang的基础&#xff0c;应该学习如下前置课程。 Golang零基础入门Golang面向对象编程Go Web 基础Go语言开发REST API接口_20240728 基础不好的同学每节课的代码最好配合视频进行阅读和学习&#xff0c;如果基础比较扎实&#xff0c;则阅读本教程巩固一下相…

Qt Designer,仿作一个ui界面的练习(二):部件内容的填充

有了完成了布局的基本框架设计之后&#xff0c;对各个部件逐步完成内容的填充。 一、还是从顶边栏开始&#xff1a; 1、在顶边栏的topLogo里面拖入一个QLabel&#xff08;标签&#xff09;&#xff0c;命名为logoImage&#xff0c;删除标签的文字。 2、右键点击topLogo&#x…

计算机三级嵌入式(三)——嵌入式系统硬件组成

目录 考点1 嵌入式最小硬件系统 考点2 基于 ARM 内核的典型嵌入式应用系统硬件组成 考点3 ARM 的 AMBA 总线体系结构及标准 考点4 基于 ARM 内核的嵌入式芯片的硬件组成 考点5 存储器层次结构 考点6 存储器分类 考点7 存储器主要性能指标 考点8 片内存储器 考点9 外部…