`
zgymm2008
  • 浏览: 12135 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Android自动化测试初探

阅读更多
基于UI Automation的自动化测试框架 收藏§

第一部分:前言
自动化测试或许是众多测试同行都在研究或准备研究的领域。结合自己的能力和公司的状况,选择合适的自动化工具、搭建正确而又高效的框架或许是个永远讨论不完的话题,正如应了那句话,没有最好,只有更好。

个人所在的公司当前开展的很多项目都是基于Win7和WPF开发的,之前想尝试用QTP对之进行录制和回放操作,不幸的是,需要额外的WPF插件支持;另外QTP的脚本语言是VBScript,虽然说是功能强大且容易上手,但是其逻辑严谨性还是不如诸多类C的高级语言。自身对QTP的掌握程度也只能算是入门级的,想到开发自动化程序前还要先深入学习QTP,感觉有点戴着枷锁跳舞。其实当前个人急切想掌握和学习的事情的自动化测试框架的知识,因为毕竟录制和编写过程化的自动化程序不是件难事,搭建出高效的框架才是核心,只有掌握了框架的东东,才能用之于四海而皆准。

在苦寻之中,UI Automation出现在了我面前。其有如下几个优点:
n   微软提供的新一代自动化framework,内嵌于.net framework,对WPF完全支持
n   编程语言采用C#
n   MSDN提供非常详细的帮助文档,并有详细的代码示例
n   弹性非常优良,只提供窗口、控件等元素的识别、动作、属性等公共方法,至于上层的架构搭建完全由编程人员自行决定

第二部分:搭建框架
         先来看一下最普通的自动化测试流程:
       
        

         如果编写一个过程化的自动化程序,每执行一个测试用例,那么很多代码和动作基本都是重复冗余的,那好吧,研究一下有哪些方面可以抽象封装的:
n   自动化程序的配置:在App.config中定义
n   测试场景套准备和清理:考虑到不同的场景之间肯定是不同的,故采用interface规范之
n   启动被测试程序
n   测试场景准备和清理:考虑到不同的场景之间肯定是不同的,故采用interface规范之
n   控件元素的组织:XML列举每个Element的几个重要属性
n   控件元素的创建
n   控件元素的行为
n   测试结果的判断
n   测试结果的存储:采用开源NLog
n   异常的处理:在底层定义用户异常类,由顶层类处理捕获这些异常

抽象封装后的框架图:

  


说明:
C#中的delegate,相当于以前的回调函数,但其优点是可以迭代添加要运行的方法链,这使得其Launch AUT所在的类中的代码在添加或删除测试用例的时候都无需进行修改。只需要在外部测试场景套中动态的添加测试场景即可,非常的方便。

类C语言还有一个优点就是良好的异常处理机制,这在多层应用程序中该优点更是显现的淋漓尽致。试想如果一个程序有十多层的函数调用,如果没有很好的异常传导和处理机制,在每层处理异常将是非常头疼的一件事情。有了该异常传导机制,底层如果遇到异常,且该异常的出现有必要终止当前自动化测试场景进行的话,只需放弃处理,且抛出该异常,那么中间层所有方法就可以不关心异常处理的操作,顶层的调用方法自然会捕获并处理该异常。这在编写中间层方法的时候是一件非常爽的事情,因为你只要按照正常流程去编写方法就可以了,不需要去关心那些异常和与之应该作出的动作。(这里并不是说像VBScript没有此项功能,相反VBScript也有相类似的功能,可参看我另一篇博文:VBScript 的异常传递与处理§)

第三部分:后记
搭建框架的时候发现一些问题,那就是你如果想使自己搭建的自动化测试程序框架能高效且以后变动尽可能的小,那么就需要完全走一遍软件开发的过程:

n   分析自动化测试需求
n   架构设计
n   模式设计
对于这些方面,自己还是比较欠缺。努力学习吧!



Android自动化测试初探(二): Hierarchyviewer 捕获Element的实现原理 收藏§

                Android SDK tools下的工具hierarchyviewer可以展现Device上的Element的层次分布和自身属性,其核心函数之一就是LoadScene,研究后发现其实现方法是向Device的4939端口通过socket的方式发送了一个DUMP的命令,Device会自动处理该命令并将所有Screen上的Element层次结构和属性一并发回,实现代码如下:
public static void listElement(IDevice device){
Socket socket;
      BufferedReader in;
      BufferedWriter out;
      socket = null;
      in = null;
      out = null;
          
      do{
        DeviceBridge.setupDeviceForward(device);
      }while(4939!=DeviceBridge.getDeviceLocalPort(device));
          
      socket = new Socket();
      try {
socket.connect(new InetSocketAddress("127.0.0.1", DeviceBridge.getDeviceLocalPort(device)));

out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
          
System.out.println("==> DUMP");
out.write((new StringBuilder()).append("DUMP -1").toString());
          
out.newLine();
            out.flush();
            do
            {
                  String line;
if ((line = in.readLine()) == null || "DONE.".equalsIgnoreCase(line))
                        break;
                  line = line.trim();
                  System.out.println(line);
            } while (true);
      } catch (IOException e) {
                  e.printStackTrace();
      }
}
运行后的结果摘录其中一部分(button5),列举如下。注:当前device中运行的是2.1SDK中自带的Calculator程序:
com.android.calculator2.ColorButton@43b8bee8 mText=1,5 getEllipsize()=4,null mMinWidth=1,0 mMinHeight=1,0 mMeasuredWidth=2,79 mPaddingBottom=1,0 mPaddingLeft=1,0 mPaddingRight=1,0 mPaddingTop=1,0 mMeasuredHeight=2,78 mLeft=2,81 mPrivateFlags_DRAWING_CACHE_INVALID=3,0x0 mPrivateFlags_DRAWN=4,0x20 mPrivateFlags=8,16779312 mID=9,id/digit5 mRight=3,160 mScrollX=1,0 mScrollY=1,0 mTop=1,0 mBottom=2,78 mUserPaddingBottom=1,0 mUserPaddingRight=1,0 mViewFlags=9,402669569 getBaseline()=2,54 getHeight()=2,78 layout_gravity=4,NONE layout_weight=3,1.0 layout_bottomMargin=1,0 layout_leftMargin=1,1 layout_rightMargin=1,0 layout_topMargin=1,0 layout_height=11,FILL_PARENT layout_width=11,FILL_PARENT getTag()=4,null getVisibility()=7,VISIBLE getWidth()=2,79 hasFocus()=5,false isClickable()=4,true isDrawingCacheEnabled()=5,false isEnabled()=4,true isFocusable()=4,true isFocusableInTouchMode()=5,false isFocused()=5,false isHapticFeedbackEnabled()=4,true isInTouchMode()=4,true isOpaque()=5,false isSelected()=5,false isSoundEffectsEnabled()=4,true willNotCacheDrawing()=5,false willNotDraw()=5,false
另外还支持如下命令:
- LIST will show the list of windows:
LIST
43514758 com.android.launcher/com.android.launcher.Launcher
4359e4d0 TrackingView
435b00a0 StatusBarExpanded
43463710 StatusBar
43484c58 Keyguard
DONE.





Android自动化测试初探(三): 架构实现 收藏§

       前两节讲了用Android SDK自带的tool-hierarchyviewer来捕获Activity上Element,并分析了其中的原理。对于要实现GUI自动化,还有哪些工作没有完成呢?
n   Invoke界面上的Element,如点击按钮,在文本框中输入内容等
n   Press手机自身所有的按键,如HOME键,Menu键,左右上下方向键,通话键,挂机键等
n  判断测试结果
前面说过,直接从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实现模拟键盘鼠标事件主要通过以下三个部分组成:
l   Socket编程:实现PC和Emulator通讯,并进行循环监听
l   Service服务:将Socket的监听程序放在Service中,从而达到后台运行的目的。这里要说明的是启动服务有两种方式,bindService和startService,两者的区别是,前者会使启动的Service随着启动Service的Activity的消亡而消亡,而startService则不会这样,除非显式调用stopService,否则一直会在后台运行因为Service需要通过一个Activity来进行启动,所以采用startService更适合当前的情形
l   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;

步骤2. 循环处理Message
//在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();
}

步骤3. 在接收到Socket中的传递信息后抛出Message
handler.post( new Runnable() {
            public void run() {
Instrumentation inst=new Instrumentation();
inst.sendKeyDownUpSync(keyCode);
}
} );

2.    Touch指定坐标,如下例子即touch point(240,400)
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));
     
3.    模拟滑动轨迹
将上述方法中间添加 MotionEvent.ACTION_MOVE


Android自动化测试初探(五): 再述模拟键盘鼠标事件(adb shell 实现) 收藏§

上一篇博文中讲述了通过Socket编程从外部向Emulator发送键盘鼠标模拟事件,貌似实现细节有点复杂。其实Android还有一种更简单的模拟键盘鼠标事件的方法,那就是通过使用adb shell 命令。

1.     发送键盘事件:
命令格式1:adb shell input keyevent “value”
其中value以及对应的key code如下表所列:
KeyEvent Value
KEYCODE
Comment
0
KEYCODE_UNKNOWN

1
KEYCODE_MENU
在SDK2.1的模拟器中命令失效,sendevent命令可行
2
KEYCODE_SOFT_RIGHT

3
KEYCODE_HOME

4
KEYCODE_BACK

5
KEYCODE_CALL

6
KEYCODE_ENDCALL

7
KEYCODE_0

8
KEYCODE_1

9
KEYCODE_2

10
KEYCODE_3

11
KEYCODE_4

12
KEYCODE_5

13
KEYCODE_6

14
KEYCODE_7

15
KEYCODE_8

16
KEYCODE_9

17
KEYCODE_STAR

18
KEYCODE_POUND

19
KEYCODE_DPAD_UP

20
KEYCODE_DPAD_DOWN

21
KEYCODE_DPAD_LEFT

22
KEYCODE_DPAD_RIGHT

23
KEYCODE_DPAD_CENTER

24
KEYCODE_VOLUME_UP

25
KEYCODE_VOLUME_DOWN

26
KEYCODE_POWER

27
KEYCODE_CAMERA

28
KEYCODE_CLEAR

29
KEYCODE_A

30
KEYCODE_B

31
KEYCODE_C

32
KEYCODE_D

33
KEYCODE_E

34
KEYCODE_F

35
KEYCODE_G

36
KEYCODE_H

37
KEYCODE_I

38
KEYCODE_J

39
KEYCODE_K

40
KEYCODE_L

41
KEYCODE_M

42
KEYCODE_N

43
KEYCODE_O

44
KEYCODE_P

45
KEYCODE_Q

46
KEYCODE_R

47
KEYCODE_S

48
KEYCODE_T

49
KEYCODE_U

50
KEYCODE_V

51
KEYCODE_W

52
KEYCODE_X

53
KEYCODE_Y

54
KEYCODE_Z

55
KEYCODE_COMMA

56
KEYCODE_PERIOD

57
KEYCODE_ALT_LEFT

58
KEYCODE_ALT_RIGHT

59
KEYCODE_SHIFT_LEFT

60
KEYCODE_SHIFT_RIGHT

61
KEYCODE_TAB

62
KEYCODE_SPACE

63
KEYCODE_SYM

64
KEYCODE_EXPLORER

65
KEYCODE_ENVELOPE

66
KEYCODE_ENTER

67
KEYCODE_DEL

68
KEYCODE_GRAVE

69
KEYCODE_MINUS

70
KEYCODE_EQUALS

71
KEYCODE_LEFT_BRACKET

72
KEYCODE_RIGHT_BRACKET

73
KEYCODE_BACKSLASH

74
KEYCODE_SEMICOLON

75
KEYCODE_APOSTROPHE

76
KEYCODE_SLASH

77
KEYCODE_AT

78
KEYCODE_NUM

79
KEYCODE_HEADSETHOOK

80
KEYCODE_FOCUS

81
KEYCODE_PLUS

82
KEYCODE_MENU

83
KEYCODE_NOTIFICATION

84
KEYCODE_SEARCH

85
TAG_LAST_KEYCODE


命令格式2:adb shell sendevent [device] [type]  [value]
如: adb shell sendevent /dev/input/event0 1 229 1 代表按下按下menu键
       adb shell sendevent /dev/input/event0 1 229 0 代表按下松开menu键
说明:上述的命令需组合使用
另外所知道的命令如下:
Key Name                        CODE
MENU                                 229
HOME                                 102
BACK (back button)            158
CALL (call button)               231
END (end call button)         107

2.     发送鼠标事件(Touch):
命令格式:adb shell sendevent [device] [type]  [value]

情况1:在某坐标点上touch
如在屏幕的x坐标为40,y坐标为210的点上touch一下,命令如下
adb shell sendevent /dev/input/event0 3 0 40
adb shell sendevent /dev/input/event0 3 1 210

adb shell sendevent /dev/input/event0 1 330 1 //touch
adb shell sendevent /dev/input/event0 0 0 0       //it must have

adb shell sendevent /dev/input/event0 1 330 0 //untouch
adb shell sendevent /dev/input/event0 0 0 0 //it must have

注:以上六组命令必须配合使用,缺一不可

情况2:模拟滑动轨迹(可下载并采用aPaint软件进行试验)
如下例是在aPaint软件上画出一条开始于(100,200),止于(108,200)的水平直线
adb shell sendevent /dev/input/event0 3 0 100 //start from point (100,200)
adb shell sendevent /dev/input/event0 3 1 200

adb shell sendevent /dev/input/event0 1 330 1 //touch
adb shell sendevent /dev/input/event0 0 0 0

adb shell sendevent /dev/input/event0 3 0 101 //step to point (101,200)
adb shell sendevent /dev/input/event0 0 0 0
……………………                                                  //must list each step, here just skip
adb shell sendevent /dev/input/event0 3 0 108 //end point(108,200)
adb shell sendevent /dev/input/event0 0 0 0

adb shell sendevent /dev/input/event0 1 330 0 //untouch
adb shell sendevent /dev/input/event0 0 0 0



分享到:
评论

相关推荐

    Android自动化测试初探.doc

    【Android自动化测试初探】 Android自动化测试是一种针对Android应用程序进行的自动化的质量验证过程,它旨在减少手动测试的重复劳动,提高测试效率和覆盖率。在Android系统中,自动化测试通常涉及UI测试、功能测试...

    android自动化测试资料

    3.Create_Android_Sample_...Android自动化测试初探 Android自动化测试可行性途径分析 Android自动化测试之道 GSM手机自动化测试解决方案 手机自动化测试系统设计浅析 在Android_Robotium自动化测试中导出Test_result

    android自动化

    ### Android自动化测试初探 #### 一、前言与背景 随着移动互联网的快速发展,Android作为全球最大的移动操作系统之一,在其应用开发过程中面临着各种各样的挑战。为了确保应用的质量,测试变得尤为重要。传统上,...

    Android开发技巧总汇(2)

    4. **Android自动化测试初探** - 自动化测试在Android开发中非常重要,可以帮助开发者快速定位问题并确保应用质量。Android提供了多种测试框架,如JUnit、Espresso等。 - **捕获Activity上的Element**:可以使用...

    安卓开发技巧总汇

    #### Android自动化测试初探 随着应用程序复杂度的增加,自动化测试变得越来越重要。它不仅可以帮助开发者快速定位问题,还能确保应用在不同设备和操作系统版本上的稳定性。在Android中,主要的自动化测试工具包括...

    Android开发技巧总汇(续)

    Android开发技巧总汇(续)又收集了两份关于android开发的写技巧知识,主要关于Activity,Context menus,Android自动化测试初探,java mail包实现发Gmail邮件,线程的处理,四种动画等等

    Android 开发技巧

    9.86、ANDROID自动化测试初探 324 9.86.1、捕获Activity上的Element 324 9.86.2、Hierarchyviewer 捕获Element的 328 9.86.3、架构实现 330 9.86.4、模拟键盘鼠标事件(Socket+Instrumentation实现) 332 9.86.5、再...

    Android 中的服务初探

    - Android Studio提供了调试服务的工具,如查看服务状态,模拟停止服务等,方便开发者测试和优化服务。 10. **服务性能优化**: - 避免在服务中做大量计算或阻塞操作,以免影响用户体验。 - 使用JobScheduler或...

    《移动应用软件测试项目教程》读书笔记模板.pptx

    任务二:使用 MonkeyRunner 工具,学习如何使用 MonkeyRunner 工具来自动化测试 Android 应用。 项目四: Android 白盒单元测试 学习目标:掌握 Android 白盒单元测试的方法和工具。 任务一:基于 JUnit 框架的...

    三、初探Android开发-Android开发与实践

    这种方法适合自动化脚本或集成开发环境的构建流程。 综上所述,Android开发涉及多个方面,包括项目创建、AVD管理、关键文件的理解以及程序结构的掌握。通过学习这些基础知识,开发者能够顺利地开始Android应用的...

    深入浅出Android--Google手持设备应用程序设计

    最后,可能会介绍测试策略,包括单元测试和UI自动化测试,以确保应用的质量。 通过这本书,读者不仅能够学会如何编写Android应用,还能对整个Android生态系统有深入的理解,从而能够开发出高质量、用户体验优秀的...

    基于计算机软件开发的JAVA编程应用初探.zip

    Java社区有许多流行的工具,如Jenkins、Maven和Gradle,它们可以帮助自动化构建、测试和部署过程,提高软件开发的效率和质量。 总的来说,"基于计算机软件开发的JAVA编程应用初探"这份资料将带领我们从基础到高级,...

Global site tag (gtag.js) - Google Analytics