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

news2024/9/9 0:57:26

前言

上一篇文章地址:

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.coloradmin.cn/o/1958776.html

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

相关文章

Java面试八股之Spring DAO的作用

Spring DAO的作用 Spring DAO (Data Access Object) 是 Spring 框架的一个重要组成部分&#xff0c;它提供了一套用于简化数据访问操作的抽象层。Spring DAO 的核心目的是使开发人员能够更容易地处理数据访问相关的异常&#xff0c;并提供一致的异常处理机制&#xff0c;同时简…

翻译: 可视化深度学习神经网络一

这是一个随意书写的28*28像素、分辨率很低的数字 3 但你的大脑一看见就能轻松辨识出来 &#xff0c;我想要你好好欣赏这点 人脑能够毫无障碍地辨识是非常厉害的 我的意思是&#xff0c;这个、这个、还有这个&#xff0c;都能被识别为 3 即使前后图像的图形组成有很大差异 当你…

什么情况?我代码没了

前两天检视代码时&#xff0c;发现PR里面有两个提交的描述信息一模一样&#xff0c;于是我提出应该将这两个提交合并成一个&#xff0c;保持提交树的清晰。 1 先储存起来&#xff01; 而同事这时正在开发别的特性&#xff0c;工作区不是干净的&#xff0c;没法直接执行 git r…

c程序杂谈系列(职责链模式与if_else)

从处理器的角度来说&#xff0c;条件分支会导致指令流水线的中断&#xff0c;所以控制语句需要严格保存状态&#xff0c;因为处理器是很难直接进行逻辑判断的&#xff0c;有可能它会执行一段时间&#xff0c;发现出错后再返回&#xff0c;也有可能通过延时等手段完成控制流的正…

python生成二维码指向说明书

python生成二维码转向文档 python生成二维码指向说明书 import qrcode# 生成包含本地文档路径的二维码 def generate_qrcode(local_file_path):qr qrcode.QRCode(version1,error_correctionqrcode.constants.ERROR_CORRECT_L,box_size10,border4,)qr.add_data(local_file_pa…

为什么要做边界值测试?

边界值测试的理解 边界值测试&#xff08;Boundary Value Testing&#xff09;是一种常用的软件测试方法&#xff0c;它侧重于测试输入值的边缘或临界条件。这些边缘条件通常包括最小值、最大值以及接近这些最小值和最大值的值。边界值测试的基本思想是&#xff0c;许多软件错…

微信支付API列表

接入前准备 更新时间&#xff1a;2023.08.24 在正式接入微信支付App服务前&#xff0c;你需要进行以下准备步骤&#xff1a; 选择接入模式&#xff1a;普通商户或普通服务商申请参数&#xff1a;AppID、商户号App支付页面规范 #选择接入模式 商户需要判断自己公司注册区域…

SuperMap GIS基础产品FAQ集锦(20240729)

一、SuperMap iDesktopX 问题1&#xff1a;您好&#xff0c;想请教一下&#xff0c;白模可以调整颜色吗 11.2.0 【解决办法】 右键白模图层&#xff0c;制作单值专题图&#xff0c;即可调整白模颜色。 问题2&#xff1a;这边有份矢量数据&#xff0c;导入到桌面里面要放很大…

Node.js + Axios 上传附件到 Gitee 仓库指定 Release

在软件开发过程中&#xff0c;自动化发布流程是提升效率的关键环节之一。本文将介绍如何使用 Node.js 和 Axios 库来自动化地向 Gitee 仓库的最新版本中上传发布包。通过读取项目中的 package.json 文件&#xff0c;获取版本信息&#xff0c;并自动将构建好的包文件上传到 Gite…

我们的前端开发逆天了!1 小时搞定了新网站,还跟我说 “不要钱”

大家好&#xff0c;我是程序员鱼皮。前段时间我们上线了一个新软件 剪切助手 &#xff0c;并且针对该项目做了一个官网&#xff1a; 很多同学表示官网很好看&#xff0c;还好奇是怎么做的&#xff0c;其实这个网站的背后还有个有趣的小故事。。。 鱼皮&#xff1a;我们要做个官…

【gofar远为门锁】酒店智能门锁源码 对接收银CyberWinApp-SAAS本地化-未来之窗行业应用跨平台架构

通过写房卡按钮写房卡 一、查看门锁读卡器信息 二、玄武星辰查到对应名称 如何知道自己家门锁的app&#xff0c;使用未来之窗【玄武芯辰】查询 通过上面我看出叫做gofar 在【玄武芯辰】输入gofar&#xff0c;人工智能会提示app信息 三、设置门锁控制app 在上一步找到app&a…

web服务器配置-(apache+nginx)

⼀、web基本概念和常识 Web&#xff1a;为⽤户提供的⼀种在互联⽹上浏览信息的服务&#xff0c;Web 服务是动态的、可交互的、跨平台的和图形化的。 Web 服务为⽤户提供各种互联⽹服务&#xff0c;这些服务包括信息浏览服务&#xff0c;以及各种交互式服务&#xff0c;包括聊…

LinuxCentos中安装apache网站服务详细教程

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f427;Linux基础知识(初学)&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; &#x1f510;Linux中firewalld防火墙&#xff1a;点击&#xff01; ⏰️创作…

【Opencv】色彩空间 color space

import os import cv2 img cv2.imread(os.path.join(.,dog.jpg)) # 在opencv中使用imread,读取的图片每个像素都是bgr色彩&#xff0c;蓝色&#xff0c;绿色&#xff0c;红色 cv2.imshow(img,img) cv2.waitKey(0) # 颜色空间转化&#xff1a;BGR2RGB img_rgb cv2.cvtC…

爱快路由的dns强制客户端代理真是个强大的功能

大致情况是这样的&#xff1a;同事说在linux服务器/etc/resolv.conf上随便写个IP地址【不在线的】&#xff0c;dns地址也能解析&#xff0c;让我帮忙查查。 我看了下也感觉纳闷&#xff0c;试了下不光在服务器上&#xff0c;我本地的pc随便设置了个dns解析也是一样的。 通过wir…

【黄啊码】零代码动手创建ModelScope Agent

还没开始学习&#xff0c;先来回复一下&#xff0c;什么是Agent Agent包含的模块 好了&#xff0c;开始发放干货&#xff1a; 1、创建通义千问API (新注册用户有一定的限时免费额度) 2、登录阿里云账号&#xff0c;打开 DashScope管理控制台&#xff0c;开通 DashScope灵积模…

C#网络连接:TCP/IP模式下的网络连接与同步

1&#xff0c;目的 为了测试局域网的消息同步&#xff0c;简单写了下TCP/IP模式的同步&#xff0c;参考这个帖子。 2&#xff0c;核心库部分 using System; using System.Net; using System.Net.Sockets; using System.Text;namespace Coldairarrow.Util.Sockets {/// <s…

【React】useEffect 钩子详解

文章目录 一、useEffect 概念二、useEffect 的基本用法1. 无依赖项2. 空依赖项数组3. 带依赖项的 useEffect 三、useEffect 的常见应用场景1. 数据获取2. 订阅与清除3. 动画与定时器 四、useEffect 的进阶用法1. 多个 useEffect2. 条件执行副作用 五、注意事项 useEffect 是 Re…

playbooks 分布式部署 LNMP

1、环境配置 ansible 服务器 192.168.10.10nginx 服务器 192.168.10.20mysql 服务器 192.168.10.21php 服务器 192.168.10.22 2、安装 ansble #192.168.10.10节点 yum install -y epel-release #先安装 epel 源 yum install -y ansible配置主机清单 …

Vue 动态改变css文件

theme: smartblue 一、背景需求 现有 Vue3 项目&#xff0c;要求点击按钮后&#xff0c;会动态加载css文件内容 二、实现过程 2.1 相关代码 假设有 blue.css 和 red.css,要求点击加载对应文件 若想切换为原版样式&#xff0c;点击 back 回退到初始样式 this is a simple text …