Android自动化测试初探(三): 架构实现
2012-12-23 15:01
232 查看
前两节讲了用Android SDK自带的tool-hierarchyviewer来捕获Activity上Element,并分析了其中的原理。对于要实现GUI自动化,还有哪些工作没有完成呢?
* Invoke界面上的Element,如点击按钮,在文本框中输入内容等
* Press手机自身所有的按键,如HOME键,Menu键,左右上下方向键,通话键,挂机键等
* 判断测试结果
前面说过,直接从Emulator内部获取当前Activity上的Element这条路已经断了,同理,探索像UI Automation上一样Invoke Element的操作估计是行不通了,因为你拿不到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表示后跟一位信息。
至此,问题似乎都解决掉了。画个基础架构图做个总结:
通过Socket + Instrumentation实现模拟键盘鼠标事件主要通过以下三个部分组成:
* Socket编程:实现PC和Emulator通讯,并进行循环监听
* Service服务:将Socket的监听程序放在Service中,从而达到后台运行的目的。这里要说明的是启动服务有两种方式,bindService和startService,两者的区别是,前者会使启动的Service随着启动Service的Activity的消亡而消亡,而startService则不会这样,除非显式调用stopService,否则一直会在后台运行因为Service需要通过一个Activity来进行启动,所以采用startService更适合当前的情形
* Instrumentation发送键盘鼠标事件:Instrumentation提供了丰富的以send开头的函数接口来实现模拟键盘鼠标,如下所述:
sendCharacterSync(int keyCode) //用于发送指定KeyCode的按键
sendKeyDownUpSync(int key) //用于发送指定KeyCode的按键
sendPointerSync(MotionEvent event) //用于模拟Touch
sendStringSync(String text) //用于发送字符串
注意:以上函数必须通过Message的形式抛到Message队列中。如果直接进行调用加会导致程序崩溃。
对于Socket编程和Service网上有很多成功的范例,此文不再累述,下面着重介绍一下发送键盘鼠标模拟事件的代码:
1. 发送键盘KeyCode:
步骤1. 声明类handler变量
步骤2. 循环处理Message
步骤3. 在接收到Socket中的传递信息后抛出Message
2. Touch指定坐标,如下例子即touch point(240,400)
3. 模拟滑动轨迹
将上述方法中间添加 MotionEvent.ACTION_MOVE
* Invoke界面上的Element,如点击按钮,在文本框中输入内容等
* Press手机自身所有的按键,如HOME键,Menu键,左右上下方向键,通话键,挂机键等
* 判断测试结果
前面说过,直接从Emulator内部获取当前Activity上的Element这条路已经断了,同理,探索像UI Automation上一样Invoke Element的操作估计是行不通了,因为你拿不到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自动化测试初探(四): 模拟键盘鼠标事件(Socket+Instrumentation实现)
通过Socket + Instrumentation实现模拟键盘鼠标事件主要通过以下三个部分组成:* Socket编程:实现PC和Emulator通讯,并进行循环监听
* Service服务:将Socket的监听程序放在Service中,从而达到后台运行的目的。这里要说明的是启动服务有两种方式,bindService和startService,两者的区别是,前者会使启动的Service随着启动Service的Activity的消亡而消亡,而startService则不会这样,除非显式调用stopService,否则一直会在后台运行因为Service需要通过一个Activity来进行启动,所以采用startService更适合当前的情形
* Instrumentation发送键盘鼠标事件:Instrumentation提供了丰富的以send开头的函数接口来实现模拟键盘鼠标,如下所述:
sendCharacterSync(int keyCode) //用于发送指定KeyCode的按键
sendKeyDownUpSync(int key) //用于发送指定KeyCode的按键
sendPointerSync(MotionEvent event) //用于模拟Touch
sendStringSync(String text) //用于发送字符串
注意:以上函数必须通过Message的形式抛到Message队列中。如果直接进行调用加会导致程序崩溃。
对于Socket编程和Service网上有很多成功的范例,此文不再累述,下面着重介绍一下发送键盘鼠标模拟事件的代码:
1. 发送键盘KeyCode:
步骤1. 声明类handler变量
private static Handler handler; |
//在Activity的onCreate方法中对下列函数进行调用 private void createMessageHandleThread(){ //need start a thread to raise looper, otherwise it will be blocked Thread t = new Thread() { public void run() { Log.i( TAG,"Creating handler ..." ); Looper.prepare(); handler = new Handler(){ public void handleMessage(Message msg) { //process incoming messages here } }; Looper.loop(); Log.i( TAG, "Looper thread ends" ); } }; t.start(); } |
handler.post( new Runnable() { public void run() { Instrumentation inst=new Instrumentation(); inst.sendKeyDownUpSync(keyCode); } } ); |
Instrumentation inst=new Instrumentation(); 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)); |
将上述方法中间添加 MotionEvent.ACTION_MOVE
相关文章推荐
- Mahout架构初探及KMeans算法分布式实现的研究
- Android自动化测试初探(二): Hierarchyviewer 捕获Element的实现原理
- Mahout架构初探及KMeans算法分布式实现的研究
- Spring AOP 织入初探--通过架构看实现
- Android自动化测试初探(三): 架构实现
- Android自动化测试初探(三): 架构实现
- Intel芯片架构中TEE的实现技术之SGX初探
- Android自动化测试初探(三): 架构实现
- Android自动化测试初探(三): 架构实现
- Android自动化测试初探(三): 架构实现
- Android自动化测试初探(五): 再述模拟键盘鼠标事件(adb shell 实现)
- Android自动化测试初探(二): Hierarchyviewer 捕获Element的实现原理
- Android自动化测试初探(三): 架构实现
- ANDROID的 BLUETOOTH 实现机制与架构
- 聊聊高并发长连接架构:百万在线的美拍直播弹幕系统如何实现
- 单一世界架构初探之终端分布
- 【凡尘工作室】 微信平台架构和实现(github开源项目)
- MySQL实现递归调用,查询组织架构树
- 初探在uCOS II上实现大容量内存文件系统
- MySQL实现递归调用,查询组织架构树