uiautomator怎么选择js如何做多级菜单选择元素

1. UiAutomator测试框架研究与实践
1.1 UiAutomator 简介:
& & 最近在工作中偶尔接触到了UiAutomator这个自动化测试框架,所以就顺便学习了一下并写了一些case在工作投入了使用。这里就将UiAutomator做一个简单的记录:
它是一个Android自动化测试框架,是谷歌在Android4.1版本发布时推出的一款用Java编写的UI测试框架。它只能用于UI也就是黑盒方面的测试。所以UiAutomator只能运行在4.1以后的版本中。其最大的特点就是可以跨进程操作,我们可以使用uiautomator框架提供的一些方便的API来对安卓应用进行一系列的自动化测试操作,如点击、滑动、键盘输入、长按以及常用的断言方法等。可以替代以前繁琐的手工测试。
下面总结一下该框架的几个优点:
Google自家推出的,其稳定性和后续的维护更新可以得到保障,运行时也有更多的权限。
可以跨进程操作,这点比起其它基于instrumentation框架的自动化工具如Robotium是无法直接做到的。
运行速度快。
不支持Android4.1以下的版本。
不支持Webview,所以一般无法对浏览器应用进行测试。
1.2 UiAutomator 框架原理分析:
&&& 首先,UiAutomator是Google参考微软的UiAutomation提供的一套用在Android上的自动化测试框架。基于Android AccessilibilityService提供。那么至于什么是AccessilibilityService,在这里简单介绍下:Android AccessilibilityService,是一个可访问服务,它是一个为增强用户界面并帮助残疾用户的应用程序,或者用户可能无法完全与设备的交互。举个简单的例子,假如一个用户在开车。那么用户就有可能需要添加额外的或者替代的用户反馈方式。其应用方式一般有两种:
第一种方法是:UiAutomatorView + monkey。它与hierachyview + monkey差不多。其区别是:UiAutomatorView通过ADB向设备侧发送一个dump命令,而不是建立一个socket,下载一个包含当前界面控件布局信息的xml文件。相比较hierachyview下载的内容而言,该文件小很多。因此,从效率上讲,这种方法比第一种应用模式快很多。
第二种方法是: 直接调用UiAutomator框架对外提供的API,主要有UiDevice、UiSelector、UiObject和 UiScrollable等。其原理与第一种方式即HierachyView + Monkey差不多。其过程大致是:首先,UiAutomator测试框架通过Accessibilityservice,获取当前窗口的控件层次关系及属性信息,并查找到目标控件。若是点击事件,则计算出该控件的中心点坐标。其次,UiAutomator通过 InputManager.getInstance().injectInputEvent隐藏接口来注入用户事件(点击、输入类操作),从而实现跨进程自动化的目的。
UiAutomator对外还提供了UiAutomatorTestCase、UiDevice、UiSelector、UiObject、UiCollection、UiScrollable等重要的类,其各自的作用如下:
UiAutomatorTestCase&:这个类是继承自Junit TestCase&(Junit),对外提供setup、teardown等,以便初始化用例、清除环境等。所以我们在编写的UiAutomator 的脚本时一般都要继承这个类,这样就可以直接使用它的一些方法和Junit单元测试框架中的Assert断言机制。
UiObject :UiObject可以代表页面的任意元素,但它的各种属性定位通常是通过UiSelector这个类来辅助完成的。
UiDevice :在测试时可以通过getUiDevice() 来实例化UiDevice对象去对设备进行各种控制,如唤醒屏幕,锁屏,点击Home, Back,Menu键等等。
UiSelector : 主要是通过一定查询方式,可以通过UiSelector对象去定位UI元素。如果发现多个满足条件的控件则会返回第一个控件,在使用UiSelector的时候可以组合使用多个属性来定位具体的控件,还可以使用childSelector()函数来嵌套UiSelector对象。
UiCollection: UiCollection一般与UiSelector连用,如它的构造函数也要求提供UiSelector: UiCollection(UiSelector selector)。它的API较少,主要用以从Uiselector筛选出的元素集中挑出所要的元素:getChildByDescription(), getChildByInstance(), getChildByText() ,以及统计元素集的个数getChildCount()。
UiScrollable:UiScrollable&用来表示可以滑动的界面元素,其继承关系为UiObject -& UiCollection -&UiScrollable。但UiAutomator的实现方式与HierachyView+Monkey有很大不一样。以控件点击操作为例,其实现流程大致如下:
定义一个点击对象Object,该对象则通过UiSelector对象定位到具体的控件。而UiSelector则通过UiAutomatorBridge(它可看做是UiSelector与AccesibilityService之间的连接器),将查询内容(AccessibilityNodeInfo)和输入事件(AccessibilityEvent)传给AccessibilityService。实际业务过程比这复杂的多。这样,就实现了对某个控件的查找或点击操作。备注:AccessibilityEvent,所有可操纵的UI元素都定义为一个AccessibilityEeventt;AccessibilityNodeInfo指视窗中的组件树节点。
未完待续。。。有空会再继续更新部分内容并添加图片进来。
阅读(...) 评论() &UIAutomator中一些类和接口的意义
介绍一下Uiautomator中每一个类,接口,异常类的作用,方便在使用的时候具体导入哪一个包
Uiautomator类中每一个类的作用:
com.android.uiautomator.core.UiCollection:
UiCollection代表元素条目的集合,例如音乐专辑中的歌曲或邮箱收件箱列表。类似UiObject,需要指定UiSelector来构造UiCollection。
用于构造UiCollection的UiSelector一般搜索容器或包裹器类的界面元素,这样的容器或包裹器类的界面元素包含其他子UI元素,例如包含子元素的布局视图。下面举例说明,下面的代码片段演示如何构造一个UiCollection实例,该实例代表一个包含在FrameLayout布局中的视频专辑
在测试时,可以调用UiDevice实例的方法来检查不同属性的状态,如当前的屏幕旋转方向货展示大小。测试代码还能使用UiDevice实例来执行设备级的操作,如强制设备横竖屏,按压d-pad硬件按钮,或按压主屏幕键和菜单键。
com.android.uiautomator.core.UiObject:
UiObject代表一个UI元素。为创建一个UiObject实例,使用用来描述如何搜索、选定UI元素的UiSelector.
com.android.uiautomator.core.UiScrollable:
UiScrollable代码可滑动的UI元素集合。可以使用UiScrollable类来模拟界面的横竖屏的滑动。该技术可以应用于界面元素隐藏在屏幕外,可以通过滑动来展示的情况下。
com.android.uiautomator.core.UiSelector:
代表一种搜索标准,可以在当前展示界面上查询和获取特定元素的句柄。若找到多于一个的匹配元素,则返回布局层次结构上的第一个匹配元素作为目标UiObject。当构造一个UiSelector对象时,可以使用链式调用多个属性来缩小查询范围。如无匹配元素,则返回异常UiAutomatorObjectNotFoundException。你还可以使用childSelector() 方法来嵌套多个Uiselector实例。例如。下面的代码演示如何制定查询来定位在当前界面的第一个ListView,然后在返回的ListView内定位一个带有Apps文本属性的界面元素。
com.android.uiautomator.core.Configurator:
运行uiautomator测试程序时设置主要的参数。
Uiautomator接口中每个接口的作用:
com.android.uiautomator.core.UiWatcher:
代表待测设备上的条件监听器
com.android.uiautomator.testrunner.IAutomationSupport:
提供运行测试的辅助支持
com.android.uiautomator.testrunner.UiAutomatorTestCase:
定义运行多个测试用例时的环境。所有的uiautomator测试用例都需要集成该类。
Exception 异常&&&&&&&&&
com.android.uiautomator.core.UiObjectNotFoundException:
UiSelector不匹配当前屏幕的界面元素时,抛出异常
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。UIAutomator怎么通过子节点查找父节点
[问题点数:40分]
UIAutomator怎么通过子节点查找父节点
[问题点数:40分]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。在本人之前的一篇文章&&Appium基于安卓的各种FindElement的控件定位方法实践和建议&&第二章节谈到Appium可以通过使用UIAutomator的方法去定位Android界面上的控件,当时只是一笔带过举了个例子。如该文给自己的承诺,今天特撰写此文以描述UIAutomator各种控件定位的方法,以作为前文的姊妹篇互通有无。 1. 背景为了和前文达成一致,这次的实践对象同样也是使用SDK自带的NotePad应用,同样是尝试去获得在NotesList那个Activity里的Menu Options上面的那个Add note菜单选项。以下是UIAutomatorViewer对界面的一个截图.
但有一个例外的地方是下文的” 通过伪xpath方法定位控件 “章节实例需要使用到的是NoteEditor这个activity里面的Menu options,因为需要演示通过子控件获得父控件然后得到兄弟控件的功能,UIAutomatorViewer截图如下。
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还支持其他一些方法,比如根据控件属性是否可点击可聚焦可长按等来缩小要定位的控件的范围,具体使用方法不一一列举,可以查看以下测试验证代码。 .UIAutomatorDimport com.android.uiautomator.core.UiDimport com.android.uiautomator.core.UiOimport com.android.uiautomator.core.UiObjectNotFoundEimport com.android.uiautomator.core.UiSimport com.android.uiautomator.core.UiSimport com.android.uiautomator.testrunner.UiAutomatorTestCimport static org.hamcrest.Matchers.*;import static org.hamcrest.MatcherAssert.assertTpublic 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 = if(noteList.exists()) {
note = noteList.getChildByText(new UiSelector().className(&android.widget.TextView&), &Note1&, true);
//note = noteList.getChildByText(new UiSelector().text(&Note1&), &Note1&, true);
note = new UiObject(new UiSelector().text(&Note1&)); } assertNotNull(note);
//Go to the NoteEditor activity note.click(); device.pressMenu();
UiObject save = UiObject delete =
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&);}

我要回帖

更多关于 jquery多级菜单 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信