Android自动化测试.docx
- 文档编号:7120698
- 上传时间:2023-01-20
- 格式:DOCX
- 页数:38
- 大小:55.99KB
Android自动化测试.docx
《Android自动化测试.docx》由会员分享,可在线阅读,更多相关《Android自动化测试.docx(38页珍藏版)》请在冰豆网上搜索。
Android自动化测试自动化测试Android自动化测试初探-1:
捕获Activity上的Element第一部分:
前言Android系统下应用程序的测试现在应该还算是个新的领域,网上关于这方面的资料很多都是基于白盒测试的,一般都是基于JUnit框架和AndroidSDK中android.test等命名空间下的内容进行,但是有一个前提,那就是必须要有应用程序的源代码以提供测试接入点,但是这在很多软件公司中是不现实的。
很多测试工程师做的工作是完全黑盒,基本接触不到源代码,白盒测试大部分也是由开发自己完成。
回顾一下Windows下的黑盒测试自动化,先前使用的是微软提供的基于.netframework的UIAutomation自动化测试框架(要求版本在.netframework3.0以上,即VS.NET2008开发环境),对与擅长C#语言的人来说,使用起来确认比较好用。
本人也写了基于UIAutomation的轻量级的自动化框架,将在以后的博文中引出。
那在Android操作系统中能不能做类似于UIAutomation的事情呢?
不幸的是,Android的权限控制分的非常清楚,不同程序之间的数据访问只能通过Intent,contentprovider类似的功能实现。
也就是说你开发的运行在Android中的自动化程序想要捕获当前运行的AUT(ApplicationunderTest)界面上的控件等Element(该术语引自UIAutomation,觉得翻译成元素有点生硬,故不作翻译)基本不可能,你也拿不到当前activeactivity的引用(截止本文发帖为止,个人暂时没有找到办法获得此引用)。
无路可走了?
模拟器里面不能走,外面能不能走?
或许可以。
第二部分:
捕获Activity上的Element在Android的SDK中自带了一个对自动化测试比较有用的工具:
hierarchyviewer(位于SDK的tools目录下)。
在模拟器运行的情况下,使用该工具可以将当前的Activity上的Element以对象树的形式展现出来,每个Element所含的属性也能一一尽显。
这有点像Windows上运行的UISPY,唯一遗憾的是不支持事件的触发。
不过没有关系,可以想办法绕,当务之急是能在自行编写的自动化测试代码里找到Activity上的Element。
第一个想到的办法就是看hierarchyviewer源码,不巧,网上搜了一下,没有资源。
或许Google的官网上有,但是上不去。
看来只能反编译了,找来XJad,暴力之。
虽然反编译出来的代码很多地方提示缺少import,但代码基本上是正确的。
看了一下,确实也知道了许多。
后来在编写代码的过程中,确实也证明了如果想引用hierarchyviewer.jar这个包并调试,还是需要知道里面的一些设置的。
创建基于hierarchyviewer.jar这个包的调用,需要将它和另外两个包,ddmlib.jar(在hierarchyviewer.jar同级目录中有)和org-netbeans-api-visual.jar(需要下载并安装netbeans,在其安装目录中有)一并导入到工程项目中,因为hierarchyviewer的实现依附于这两个包。
想在代码中获取Activity上的Element需要进行如下几个步骤(如果使用过hierarchyviewer这个工具后会发现,自动化代码所要写的就是该工具上的使用步骤):
1.Ensureadbrunning2.Setadblocation(因为hierarchyviewer和模拟器的沟通完全是依靠adb做的,所以设定正确的adb程序的位置至关重要,本人就曾在这个问题上栽了半天多)3.GetActiveDevice(这个等同动作发生在启动hierarchyviewer工具时)4.StartViewServer(等同于工具上StartServer菜单触发事件)5.LoadScene(等同于工具上LoadViewHierarchy菜单触发事件)6.GetRootViewNode(获得对象树的根节点,这个动作在工具上点击LoadViewHierarchy菜单后会自动加载)7.GetSubViewNode(获得想要查找的ViewNode,这个动作在工具上点击LoadViewHierarchy菜单后会自动加载)说明:
上述步骤中一些名称实际上就是hierarchyviewer中所提供的可访问方法名称,如startViewServer、loadScene、rootNode等。
另外ViewNode实际上hierarchyviewer中的一个类,表示的对象树上的一个Element。
现将部分核心代码粘贴如下:
1.SetadblocationSystem.setProperty(hierarchyviewer.adb,E:
Androidandroid-sdk-windowstools);其中”hierarchyviewer.adb”这个key是hierarchyviewer.jar中指定的,后面的value是存放AndroidSDK的路径。
这个目录必须是当前运行的模拟器所对应的adb的目录,不能自行使用其他目录下adb,否则会发生adb进程异常退出的错误。
2.GetActiveDeviceIDevicedevices=null;DeviceBridge.terminate();while(null=devices|0=devices.length)DeviceBridge.initDebugBridge();/itmustwaitforsometime,otherwisewillthrowexceptiontryThread.sleep(1000);catch(InterruptedExceptione)e.printStackTrace();devices=DeviceBridge.getDevices();returndevices;以上方法返回的是所有当前运行的Device列表3.StartViewServerDeviceBridge.startViewServer(device);4.LoadSceneViewHierarchyLoader.loadScene(device,Window.FOCUSED_WINDOW);5.GetRootViewNodevhs.getRoot();其中vhs是ViewHierarchyScene的实例对象6.GetSubViewNodepublicViewNodefindFirstChildrenElement(IDevicedevice,ViewNodeentryViewNode,StringelementID)ViewNodenode=null;if(0!
=entryViewNode.children.size()for(inti=0;iDUMP);out.write(newStringBuilder().append(DUMP-1).toString();out.newLine();out.flush();doStringline;if(line=in.readLine()=null|DONE.equalsIgnoreCase(line)break;line=line.trim();System.out.println(line);while(true);catch(IOExceptione)e.printStackTrace();运行后的结果摘录其中一部分(button5),列举如下。
注:
当前device中运行的是2.1SDK中自带的Calculator程序:
com.android.calculator2.ColorButton43b8bee8mText=1,5getEllipsize()=4,nullmMinWidth=1,0mMinHeight=1,0mMeasuredWidth=2,79mPaddingBottom=1,0mPaddingLeft=1,0mPaddingRight=1,0mPaddingTop=1,0mMeasuredHeight=2,78mLeft=2,81mPrivateFlags_DRAWING_CACHE_INVALID=3,0x0mPrivateFlags_DRAWN=4,0x20mPrivateFlags=8,16779312mID=9,id/digit5mRight=3,160mScrollX=1,0mScrollY=1,0mTop=1,0mBottom=2,78mUserPaddingBottom=1,0mUserPaddingRight=1,0mViewFlags=9,402669569getBaseline()=2,54getHeight()=2,78layout_gravity=4,NONElayout_weight=3,1.0layout_bottomMargin=1,0layout_leftMargin=1,1layout_rightMargin=1,0layout_topMargin=1,0layout_height=11,FILL_PARENTlayout_width=11,FILL_PARENTgetTag()=4,nullgetVisibility()=7,VISIBLEgetWidth()=2,79hasFocus()=5,falseisClickable()=4,trueisDrawingCacheEnabled()=5,falseisEnabled()=4,trueisFocusable()=4,trueisFocusableInTouchMode()=5,falseisFocused()=5,falseisHapticFeedbackEnabled()=4,trueisInTouchMode()=4,trueisOpaque()=5,falseisSelected()=5,falseisSoundEffectsEnabled()=4,truewillNotCacheDrawing()=5,falsewillNotDraw()=5,false另外还支持如下命令:
-LISTwillshowthelistofwindows:
LIST43514758com.android.launcher/com.android.launcher.Launcher4359e4d0TrackingView435b00a0StatusBarExpanded43463710StatusBar43484c58KeyguardDONE.Android自动化测试初探-3:
架构实现前两节讲了用AndroidSDK自带的tool-hierarchyviewer来捕获Activity上Element,并分析了其中的原理。
对于要实现GUI自动化,还有哪些工作没有完成呢?
nInvoke界面上的Element,如点击按钮,在文本框中输入内容等nPress手机自身所有的按键,如HOME键,Menu键,左右上下方向键,通话键,挂机键等n判断测试结果前面说过,直接从Emulator内部获取当前Activity上的Element这条路已经断了,同理,探索像UIAutomation上一样InvokeElement的操作估计是行不通了,因为你拿不到Element的对象实例,所以实例所支持的方法当然也没有办法拿到。
怎么办?
实在不行,基于坐标来对Element进行触发总可以吧。
在Windows中发送基于坐标发送键盘和鼠标事件一般是在无法识别Element的情况下,想的最后一招,这使我想起起了Android中的monkey测试,对着屏幕就是一通乱点,压根就不管点的是什么。
所幸的是,当前Android系统中我们得到了Element的属性信息,其中就包括坐标信息,而且这种信息是具有弹性的,也就是说即使Element的坐标随着开发的改变而有所变化,也不用担心,因为当前的坐标是实时获得的。
那么怎样才能给Element发送模拟按键等操作呢?
总不能用Windows当前的键盘和鼠标事件吧,那样一旦模拟器的位置改变或失去焦点,啥都白搭,风险太大了。
看来给Emulator内部发送模拟按键等操作比较靠谱。
查了一下SDK,其中确实有这样的方法存在,但是我们当前的测试基础架构程序位于Emulator外部,怎么办?
突然想起了hierarchyviewer的实现机制,通过Socket来发送信息。
Hierarchyviewer有系统自带的进程给予答复响应(具体是哪个进程进行的响应不清楚,没有研究过)。
那么我们也来模拟做一个Listener总可以吧。
其实对于模拟按键发送,网上的帖子很多,但大部分是基于一种方式实现的,IWindowManager接口。
不巧的是,SDK并没有将该接口提供为public,所以需要用android源码替代android.jar包进行编译的方式进行绕行,感觉方法有点复杂。
在后面另一篇系列文章中我会列出我在网上看到的另一种基于Instrumentation和MessageQueue的机制实现方法。
最后就剩下判断测试结果了。
判断测试结果一般分为如下两种:
外部条件是否满足,如文件是否产生,数据是否生成等;内部条件是否满足,如对应的Element是否出现或消失,Element上内容如字符串是否有变化。
对于前一种本文不予讨论,后一种情况下,Element出现或消失可以通过hierarchyviewer来获取。
仔细研究过hierarchyviewer会发现,它并没有提供Element界面上内容(Text)的属性。
这可有点晕了,好像又要回到实现捕获Activity实例的老路上来了。
考虑图像识别?
这好像不靠谱。
突然想到,4939端口上发送DUMP命令后的返回结果中会不会有此类hierarchyviewer没有显示出来的信息呢,万幸,还真有。
在我上一篇博文(Hierarchyviewer捕获Element的实现原理)中查询mText字段,会发现mText=1,5这样的信息,其实就是代表了计算器Button5上显示的内容5,逗号前的1表示后跟一位信息。
至此,问题似乎都解决掉了。
画个基础架构图做个总结:
Android自动化测试初探-4:
模拟键盘鼠标事件通过Socket+Instrumentation实现模拟键盘鼠标事件主要通过以下三个部分组成:
lSocket编程:
实现PC和Emulator通讯,并进行循环监听lService服务:
将Socket的监听程序放在Service中,从而达到后台运行的目的。
这里要说明的是启动服务有两种方式,bindService和startService,两者的区别是,前者会使启动的Service随着启动Service的Activity的消亡而消亡,而startService则不会这样,除非显式调用stopService,否则一直会在后台运行因为Service需要通过一个Activity来进行启动,所以采用startService更适合当前的情形lInstrumentation发送键盘鼠标事件:
Instrumentation提供了丰富的以send开头的函数接口来实现模拟键盘鼠标,如下所述:
sendCharacterSync(intkeyCode)/用于发送指定KeyCode的按键sendKeyDownUpSync(intkey)/用于发送指定KeyCode的按键sendPointerSync(MotionEventevent)/用于模拟TouchsendStringSync(Stringtext)/用于发送字符串注意:
以上函数必须通过Message的形式抛到Message队列中。
如果直接进行调用加会导致程序崩溃。
对于Socket编程和Service网上有很多成功的范例,此文不再累述,下面着重介绍一下发送键盘鼠标模拟事件的代码:
1.发送键盘KeyCode:
步骤1.声明类handler变量privatestaticHandlerhandler;步骤2.循环处理Message/在Activity的onCreate方法中对下列函数进行调用privatevoidcreateMessageHandleThread()/needstartathreadtoraiselooper,otherwiseitwillbeblockedThreadt=newThread()publicvoidrun()Log.i(TAG,Creatinghandler.);Looper.prepare();handler=newHandler()publicvoidhandleMessage(Messagemsg)/processincomingmessageshere;Looper.loop();Log.i(TAG,Looperthreadends);t.start();步骤3.在接收到Socket中的传递信息后抛出Messagehandler.post(newRunnable()publicvoidrun()Instrumentationinst=newInstrumentation();inst.sendKeyDownUpSync(keyCode););2.Touch指定坐标,如下例子即touchpoint(240,400)Instrumentationinst=newInstrumentation();inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis(),MotionEvent.ACTION_DOWN,240,400,0);inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis(),MotionEvent.ACTION_UP,240,400,0);3.模拟滑动轨迹将上述方法中间添加MotionEvent.ACTION_MOVEAndroid自动化测试初探(五):
再述模拟键盘鼠标事件(adbshell实现)上一篇博文中讲述了通过Socket编程从外部向Emulator发送键盘鼠标模拟事件,貌似实现细节有点复杂。
其实Android还有一种更简单的模拟键盘鼠标事件的方法,那就是通过使用adbshell命令。
1.发送键盘事件:
命令格式1:
adbshellinputkeyevent“value”其中value以及对应的keycode如下表所列:
KeyEventValueKEYCODEComment0KEYCODE_UNKNOWN1KEYCODE_MENU在SDK2.1的模拟器中命令失效,sendevent命令可行2KEYCODE_SOFT_RIGHT3KEYCODE_HOME4KEYCODE_BACK5KEYCODE_CALL6KEYCODE_ENDCALL7KEYCODE_08KEYCODE_19KEYCODE_210KEYCODE_311KEYCODE_412KEYCODE_513KEYCODE_614KEYCODE_715KEYCODE_816KEYCODE_917KEYCODE_STAR18KEYCODE_POUND19KEYCODE_DPAD_UP20KEYCODE_DPAD_DOWN21KEYCODE_DPAD_LEFT22KEYCODE_DPAD_RIGHT23KEYCODE_DPAD_CENTER24KEYCODE_VOLUME_UP25KEYCODE_VOLUME_DOWN26KEYCODE_POWER27KEYCODE_CAMERA28KEYCODE_CLEAR29KEYCODE_A30KEYCODE_B31KEYCODE_C32KEYCODE_D33KEYCODE_E34KEYCODE_F35KEYCODE_G36KEYCODE_H37KEYCODE_I38KEYCODE_J39KEYCODE_K40KEYCODE_L41KEYCODE_M42KEYCODE_N43KEYCODE_O44KEYCODE_P45KEYCODE_Q46KEYCODE_R47KEYCODE_S48KEYCODE_T49KEYCODE_U50KEYCODE_V51KEYCODE_W52KEYCODE_X53KEYCODE_Y54KEYCODE_Z55KEYCODE_COMMA56KEYCODE_PERIOD57KEYCODE_ALT_LEFT58KEYCODE_ALT_RIGHT59KEYCODE_SHIFT_LEFT60KEYCODE_SHIFT_RIGHT61KEYCODE_TAB62KEYCODE_SPACE63KEYCODE_SYM64KEYCODE_EXPLORER65KEYCODE_ENVELOPE66KEYCODE_ENTER67KEYCODE_DEL68KEYCODE_GRAVE69KEYCODE_MINUS70KEYCODE_EQUALS71KEYCODE_LEFT_BRACKET72KEYCODE_RIGHT_BRACKET73KEYCODE_BACKSLASH74KEYCODE_SEMICOLON75KEYCODE_APOSTROPHE76KEYCODE_SLASH77KEYCODE_AT78KEYCODE_NUM79KEYCODE_HEADSETHOOK80KEYCODE_FOCUS81KEYCODE_PLUS82KEYCODE_MENU83KEYCODE_NOTIFICATION84KEYCODE_SEARCH85TAG_LAST_KEYCODE命令格式2:
adbshellsendeventdevicetypecodevalue如:
adbshellsendevent/dev/input/event012291代表按下按下menu键adbshellsendevent/dev/input/event012290代表按下松开menu键说明:
上述的命令需组合使用另外所知道的命令如下:
KeyNameCODEMENU229HOME102BACK(backbutton)158CALL(callbutton)231END(endcallbutton)1072.发送鼠标事件(Touch):
命令格式:
adbshellsendeventdevicetypecode
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android 自动化 测试