UISelector
1、UiSelector的基本方法
UiSelector对象可以理解为一种条件对象,描述的是一种条件,可以配合UiObject使用得到某个符合条件的控件对象。
所有的方法都是public的,且都返回UiSelector类的对象。
文本方面的方法:
1.text(String text) 文本
2.textContains(String text) 文本包含
3.textMatches(String regex) 文本正则
4.textStartsWith(String text) 文本开始字符
描述方面的方法:
1.description(String desc) 描述
2.descriptionContains(String desc) 描述包含
3.descriptionMatches(String regex) 描述正则
4.descriptionStartsWith(String desc) 描述开始字符
类名方面的方法:
1.childSelector(UiSelector selector) 子类
2.className(String className) 类名
索性、实例方面的方法:
1.index(int index) 编号
2.instance(int instantce) 索引
特有属性:
1.checked(boolean val) 选择属性
2.chickable(boolean val) 点击属性
3.enabled(boolean val) enabled属性
4.focusable(boolean val) 焦点属性
5.longClickable(boolean val) 长按属性
6.scrollable(boolean val) 滚动属性
7.selected(boolean val) 选择属性
包名方面的方法:
1.packageName(String name) 包名
2.packageNameMatches(String regex) 包名正则
资源ID方面的方法:
1.resourceId(String id) 资源ID
2.resourceIdMatches(String regex) 资源ID正则
2. 通过文本信息定位
通过控件的text属性定位控件应该是最常用的一种方法了,毕竟移动应用的屏幕大小有限,存在text重复的可能性并不大,就算真的有重复,可以添加其他定位方法来缩写误差。
2.1 UISelector.text方法
addNote = new UiObject(new UiSelector().text("Add note"));
assertEquals(addNote.getText(),"Add note");
该方法通过直接查找当前界面上所有的控件来比较每个控件的text属性是否如预期值来定位控件,挺好理解的,所以就没有必要细说了。
2.2. UISelector.textContains方法
addNote = new UiObject(new UiSelector().textContains("Add"));
assertEquals(addNote.getText(),"Add note");
此方法跟以上方法类似,但是不需要输入控件的全部text信息。
2.3 UISelector.textStartsWith方法
addNote = new UiObject(new UiSelector().textStartsWith("Add"));
assertEquals(addNote.getText(),"Add note");
顾名思义,通过判断一个控件的text的开始是否和预期的字串相吻合来获得控件,其实个人觉得这个方法存在的必要性不强,因为它的功能完全可以用上面的方法或者下面的正则表达式的方法取代。况且既然你提供了textStartsWith方法,为什么你不提供个textEndWith的方法呢!
2.4 UISelector.textMatches方法
addNote = new UiObject(new UiSelector().textMatches("^Add.*"));
assertEquals(addNote.getText(),"Add note");
这个方法是通过正则表达式的方式来比较控件的text来定位控件,这里有意思的是用户使用的正则表达式是有限制的,请看该方法的官方描述:” Set the search criteria to match the visible text displayed for a widget (for example, the text label to launch an app). The text for the widget must match exactly with the string in your input argument“。第一句我们不用管它,关键是第二句,翻译过来就是” 目标控件的text(的所有内容)必须和我们输入的正则表达式完全匹配 “。什么意思呢? 意思就是你不能像往常的正则表达式那样通过比较text的部分吻合来获得控件 。以下面代码为例子:
addNote = new UiObject(new UiSelector().textMatches("^Add"));
assertEquals(addNote.getText(),"Add note");
正常来说这个正则表达式是没有问题的,它的意思就是想要“获取以Add开头的text的控件,至于Add字串口面是什么值,没有必要去管它”。但是按照我们上面的官方描述,这样子是不行的,你必须要把正则表达式补充完整以使得正而表达式和控件的text完全进行匹配,至于你用什么通配符或者字串就完全按照正则表达式的语法了。
注意这个限制在UISlector使用所有的正则表达式相关的方法中都有效哦。
3 通过控件的ClassName定位
通过这种方法定位控件存在的一个问题是很容易发生重复,所以一般都是先用这种方法去narrow down目标控件,然后再去添加其他如text判断等条件进行控件定位。
3.1 UISelector.className方法
addNote = new UiObject(new UiSelector().className("android.widget.TextView").text("Add note"));
assertEquals(addNote.getText(),"Add note");
实例中首先通过ClassName找到所有的TextView控件,然后再在这些TextView控件查找text是”Add note“的控件。
3.2 UISelector.classNameMatches方法
addNote = new UiObject(new UiSelector().classNameMatches(".*TextView$"));
assertEquals(addNote.getText(),"Add note");
通过正则表达式判断className是否和预期的一致, 注意正则表达式的限制和章节2.4描述的一致 。
4. 通过伪xpath方法定位
UISelector类提供了一些方法根据控件在界面的XML布局中的层级关系来进行定位,但是UIAutomator又没有真正的提供类似Appium的findElementWithXpath相关的方法,所以这里我就称之为伪xpath方法。
这个章节使用到的不再是NotesList那个activity里面的menu options,而是NoteEditor这个activity里面的Menu options,里面不止有一个Menu entry。
4.1 通过UiSelector.fromParent或UiObject.getFromParent方法
这种方法我觉得最有用的情况是测试代码当前在操作的是同一层级的一组控件中的某一个控件,转而又需要操作同一层级的另外一个控件的时候。下面的实例就是通过save控件的父控件找到其同一层级的兄弟控件delete。这里分别列出了通过UiObject.getFromParent方法和UiSelector.fromParent方法的实例,事实上他们的功能是一样的。
UiObject.getFromPatrent方法:
save = new UiObject(new UiSelector().text("Save"));
assertEquals(save.getText(),"Save");
delete = save.getFromParent(new UiSelector().text("Delete"));
assertEquals(delete.getText(),"Delete");
UiSelector.fromParent方法(这个例子有点迂回笨拙,但为了演示功能就将就着看吧):
delete = new UiObject(new UiSelector().text("Save").fromParent(new UiSelector().text("Delete")));
assertEquals(delete.getText(),"Delete");
4.2 通过UiSelector.childSelector或UiObject.getChild方法
这种方法是在已知父控件的时候如何快速的查找该父控件下面的子控件。
UiObject.getChild方法:
UiObject parentView = new UiObject(new UiSelector().className("android.view.View"));
save = parentView.getChild(new UiSelector().text("Save"));
assertEquals(save.getText(),"Save");
UiSelector.childSelector方法:
save = new UiObject(new UiSelector().className("android.view.View").childSelector(new UiSelector().text("Save")));
assertEquals(save.getText(),"Save");
5. 通过控件ID定位
在Android API Level18及其以上的版本增加了一个Android控件的属性ResourceId, 所以要注意在使用这种方法之前先确保你的目标测试设备和你的UIAutomoator库jar包使用的都是API Level 18以上的版本 。例如我自己使用的就是本地sdk中版本19的库: D:\Develops\AndroidSDK\platforms\android-19\uiautomator.jar
5.1 UiSelector.resourceId方法
addNote = new UiObject(new UiSelector().resourceId("android:id/title"));
assertEquals(addNote.getText(),"Add note");
5.2 UiSelector.resourceIdMatches方法
addNote = new UiObject(new UiSelector().resourceIdMatches(".+id/title"));
assertEquals(addNote.getText(),"Add note");
注意正则表达式的限制和章节2.4描述的一致
6. 通过contentDescription定位
在UiAutomator框架和使用了Uiautomator框架的Appium中,控件的属性contentDescription一直是强调开发人员需要添加进去的,因为
有些控件使用其他办法很难或者根本没有办法定位
最重要的是给每个控件的contentDescription设计个唯一值让我们可以非常快速的定位控件,让我们足够敏捷!
以下的实例并没有真正跑过的,因为Notepad应用上面的控件是没有contentDescription这个属性的,但是如果我们假设Add note这个控件的contentDescription是“AddNoteMenuDesc”的话,代码的相应写法应该就如下了。
6.1 UiSelector.description方法
addNote = new UiObject(new UiSelector().description("AddNoteMenuDesc));
assertEquals(addNote.getText(),"Add note");
</pre><h2>6.2 UiSelector.descriptionContains方法</h2></div><div><pre name="code" class="java"> addNote = new UiObject(new UiSelector().descriptionContains("AddNote"));
assertEquals(addNote.getText(),"Add note");
6.3 UiSelector.descriptionStartWith方法
addNote = new UiObject(new UiSelector().descriptionStartsWith("AddNote"));
assertEquals(addNote.getText(),"Add note");
6.4 UiSelector.descriptionMatches方法
//addNote = new UiObject(new UiSelector().descriptionMatches("^AddNote.*$"));
//assertEquals(addNote.getText(),"Add note");
7.通过其他方法定位
除了以上比较常用的方法外,UIAutomator还支持其他一些方法,比如根据控件属性是否可点击可聚焦可长按等来缩小要定位的控件的范围,具体使用方法不一一列举,可以查看以下测试验证代码。
package majcit.com.UIAutomatorDemo;
import com.android.uiautomator.core.UiDevice;
import com.android.uiautomator.core.UiObject;
import com.android.uiautomator.core.UiObjectNotFoundException;
import com.android.uiautomator.core.UiScrollable;
import com.android.uiautomator.core.UiSelector;
import com.android.uiautomator.testrunner.UiAutomatorTestCase;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
public class UISelectorFindElementTest extends UiAutomatorTestCase {
public void testDemo() throws UiObjectNotFoundException {
UiDevice device = getUiDevice();
device.pressHome();
// Start Notepad
UiObject appNotes = new UiObject(new UiSelector().text("Notes"));
appNotes.click();
//Sleep 3 seconds till the app get ready
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//Evoke the system menu option
device.pressMenu();
UiObject addNote = new UiObject(new UiSelector().text("Add note"));
assertEquals(addNote.getText(),"Add note");
addNote = new UiObject (new UiSelector().checked(false).clickable(true));
assertEquals(addNote.getText(),"Add note");
addNote = new UiObject(new UiSelector().className("android.widget.TextView").text("Add note"));
assertEquals(addNote.getText(),"Add note");
addNote = new UiObject(new UiSelector().classNameMatches(".*TextView$"));
assertEquals(addNote.getText(),"Add note");
//addNote = new UiObject(new UiSelector().description("AddNoteMenuDesc));
//assertEquals(addNote.getText(),"Add note");
//addNote = new UiObject(new UiSelector().descriptionContains("AddNote"));
//assertEquals(addNote.getText(),"Add note");
//addNote = new UiObject(new UiSelector().descriptionStartsWith("AddNote"));
//assertEquals(addNote.getText(),"Add note");
//addNote = new UiObject(new UiSelector().descriptionMatches("^AddNote.*$"));
//assertEquals(addNote.getText(),"Add note");
addNote = new UiObject(new UiSelector().focusable(true).text("Add note"));
assertEquals(addNote.getText(),"Add note");
addNote = new UiObject(new UiSelector().focused(false).text("Add note"));
assertEquals(addNote.getText(),"Add note");
//TBD
//addNote = new UiObject(new UiSelector().fromParent(selector))
addNote = new UiObject(new UiSelector().index(0).text("Add note"));
assertEquals(addNote.getText(),"Add note");
addNote = new UiObject(new UiSelector().className("android.widget.TextView").enabled(true).instance(0));
assertEquals(addNote.getText(),"Add note");
addNote = new UiObject(new UiSelector().longClickable(false).text("Add note"));
assertEquals(addNote.getText(),"Add note");
addNote = new UiObject(new UiSelector().text("Add note"));
assertEquals(addNote.getText(),"Add note");
addNote = new UiObject(new UiSelector().textContains("Add"));
assertEquals(addNote.getText(),"Add note");
addNote = new UiObject(new UiSelector().textStartsWith("Add"));
assertEquals(addNote.getText(),"Add note");
addNote = new UiObject(new UiSelector().textMatches("Add.*"));
assertEquals(addNote.getText(),"Add note");
addNote = new UiObject(new UiSelector().resourceId("android:id/title"));
assertEquals(addNote.getText(),"Add note");
addNote = new UiObject(new UiSelector().resourceIdMatches(".+id/title"));
assertEquals(addNote.getText(),"Add note");
//Go to the editor activity, need to cancel menu options first
device.pressMenu();
//Find out the new added note entry
UiScrollable noteList = new UiScrollable( new UiSelector().className("android.widget.ListView"));
//UiScrollable noteList = new UiScrollable( new UiSelector().scrollable(true));
UiObject note = null;
if(noteList.exists()) {
note = noteList.getChildByText(new UiSelector().className("android.widget.TextView"), "Note1", true);
//note = noteList.getChildByText(new UiSelector().text("Note1"), "Note1", true);
}
else {
note = new UiObject(new UiSelector().text("Note1"));
}
assertNotNull(note);
//Go to the NoteEditor activity
note.click();
device.pressMenu();
UiObject save = null;
UiObject delete = null;
save = new UiObject(new UiSelector().text("Save"));
assertEquals(save.getText(),"Save");
delete = save.getFromParent(new UiSelector().text("Delete"));
assertEquals(delete.getText(),"Delete");
delete = new UiObject(new UiSelector().text("Save").fromParent(new UiSelector().text("Delete")));
assertEquals(delete.getText(),"Delete");
save = new UiObject(new UiSelector().className("android.view.View").childSelector(new UiSelector().text("Save")));
assertEquals(save.getText(),"Save");
UiObject parentView = new UiObject(new UiSelector().className("android.view.View"));
save = parentView.getChild(new UiSelector().text("Save"));
assertEquals(save.getText(),"Save");
}
}
UISelector的更多相关文章
- Could not parse UiSelector argument: 'XXX' is not a string 错误解决办法
ebDriverWait(driver,20).until(EC.visibility_of_element_located((MobileBy.ANDROID_UIAUTOMATOR,new UiS ...
- 2.UiSelector API 详细介绍
一.UiSelector类介绍 //通过各种属性与节点关系定位组件 简单实例: public void testDemo2() throws UiObjectNotFoundException{ Ui ...
- Android无线测试之—UiAutomator UiSelector API介绍之八
对象搜索—特殊属性.节点与资源ID 一.特殊属性定位对象相关API 返回值 API 描述 UiSelector checkableboolean val) 是否可选择,一般开关组件上具有checkab ...
- Android无线测试之—UiAutomator UiSelector API介绍之七
对象搜索—索引与实例 一.索引与实例说明: 1)index:在同一级中的编号,在兄弟类中组件的编号,index从0开始 2)instance:同一个布局中同一类组件的编号,instance从0开始 二 ...
- Android无线测试之—UiAutomator UiSelector API介绍之六
对象搜索—类名与包名 一.类名属性定位对象 返回值 API 描述 UiSelector calssName(String className) 完整类名匹配 UiSelector calssNameM ...
- Android无线测试之—UiAutomator UiSelector API介绍之五
对象搜索—文本与描述 一.文本属性定位对象: 返回值 API 描述 UiSelector test(String text) 文本完全匹配 UiSelector testContains(String ...
- Android无线测试之—UiAutomator UiSelector API介绍之四
四种匹配关系介绍 一.四种匹配关系介绍: 二.举例: 匹配字符串 0123456789 1.完全匹配: 0123456789 2.包含匹配: 45678.456.678 3.正则匹配: \d{10 ...
- Android无线测试之—UiAutomator UiSelector API介绍之一
一. UiSelector类介绍: 1) UiSelector类说明: UiSelector代表一种搜索条件,可以在当前界面上查询和获取特定元素的句柄,当找到多余一个的匹配元素,则返回布局层次结构上第 ...
- appium(9)-uiautomator UiSelector
uiautomator UiSelector Appium enables searching using UiSelectors. UiScrollable is also supported.// ...
- APP定位元素之UiSelector
1.UiSelector 类介绍 功能:通过各种属性与节点关系定位组件 操作步骤:找到对象->操作对象 2.四中匹配关系的介绍 (1)完全匹配 (2)包含匹配 (3)正则匹配 (4)起始匹 例子 ...
随机推荐
- 有向图的拓扑排序——DFS
在有向图的拓扑排序--BFS这篇文章中,介绍了有向图的拓扑排序的定义以及使用广度优先搜索(BFS)对有向图进行拓扑排序的方法,这里再介绍另一种方法:深度优先搜索(DFS). 算法 考虑下面这张图: 首 ...
- .NET周报【1月第1期 2023-01-06】
国内文章 [开源]基于.net6+gtksharp实现的Linux下的图形界面串口调试工具 https://www.cnblogs.com/flykai/p/17007554.html 由于公司的上位 ...
- MySQL 更新数据 不同条件(批量)更新不同值
一般在更新时会遇到以下场景:1.全部更新:2.根据条件更新字段中的某部分内容:3.根据不同的条件更新不同的值,以下是几种场景中常用的update方法. 一.方法分类 二.具体用法 (1)根据条件更新值 ...
- echarts图例过多,折线过多颜色不知道怎么分配怎么办??优化如下
优化一:很简单,echarts自身支持legend图例分页,加了分页就优化了图例过多情况. legend['type']: 'scroll', // 添加这一行代码即可实现图例分页功能 option ...
- 今天试试NuxtJS
nuxt可以大幅缩短首屏加载时间 Progressive Web App (PWA) Support 渐进式web应用 简单说 就是让你的web应用表现的就像本地应用一样,可以添加快捷方式 打开的时候 ...
- java入门与进阶 P-2.5+P-2.6
嵌套和级联的判断 嵌套的判断 当if的条件满足或者不满足的时候要执行的语句也可以是一条if或if-else语句,这就是嵌套的if语句 else的匹配 else总是和最近的那个if匹配 tips 在if ...
- postgresql添加mysql_fdw测试过程
请先确认已经安装好mysql_fdw,如果没有配置好点这:https://www.cnblogs.com/ohsolong/p/13041989.html 1.切换至postgres用户,输入密码登录 ...
- 【Android】Android 源码方式使用 opencv 库文件
使用方法 opencv 官方的 SDK 已经有编译好的 so 库,我们可以直接使用,因此我们只需要将平台架构对应的 so 库文件以及头文件提取出来,使用 Android.mk 进行预安装,然后在需要使 ...
- Linux 安装 WIFI驱动 rtl8188gu
https://www.wyr.me/post/623 https://www.leonlu.cc/hobby/note006-rtl8188gu-linux/ 亲测:debian11,manjaro ...
- Vue14 条件渲染
转:https://blog.csdn.net/weixin_57519185/article/details/121168426 1 简介 通过指令v-show和v-if可以实现条件渲染. 它们都能 ...