使用python和android模拟器做android程序的自动化测试
来源:互联网 发布:mac俄罗斯红色号 编辑:程序博客网 时间:2024/06/07 02:02
因为前段时间业务需求,需要我们测试Android软件性能,刚开始我们使用的是Monkey+Monkeyrunner +python脚本。网上也有很多资料来讲解如何利用monkeyrunner来录制脚本,使用最多的都是通过记录坐标的方式来录制,但因为我们在程序操作中,通常都是在同一块显示区域实现页面的相互跳转,所以这种方法并不能够满足我们的需要,我想到了使用id来做,因为id能够保证控件的唯一性,并且也可以精确地定位到控件的位置。我是因为这个项目自学python,所以对python这方面很多知识并不了解,于是去网上找了很多资料,但是没有一篇完整的代码可以用来实现,我也是查了好多资料,才渐渐摸索出了实现方法,特此记录。
一.准备工作
在做测试之前,要保证我们的测试环境可以正确运行,需要我们先去搭建测试环境。
(1)保证电脑上已经安装了jdk并且环境变量等的配置已经完成
(2)安装了eclipse,用于android的开发,相信做android的人应该这些都是会用到的吧
(3)下载SDK并且完成SDK的配置(因为我们需要使用到SDK文件夹tools中的一些工具工具,所以这个是必须的)
(4)安装python IDLE(python编辑器,可以很方便的用来编写python文件),并在环境变量里面配置path
(5)android模拟器(也可以使用android自带的模拟器,但是启动实在是太慢了,太费时间,果断放弃)
我使用的是天天模拟器,网上可以下载
二.测试流程
第一步,打开模拟器,我们可以在eclipse的device下面看到当前的模拟器显示信息,如下图:
注:一定要确保模拟器连接成功了,要不然接下来会有问题。
我们在使用android获取id的时候,都是直接findViewByID(R.id.IDName),系统可以帮助我们识别是在哪一个文档中,但是python却不行,就相当于在android中你写个相对路径,就ok了,但是在python中,必须要使用绝对路径(只是打个比方哈),在python中,如果我们的控件是嵌套在几层布局之中的话,就必须通过它的根布局元素ID去一层一层往下找。通常我们写的界面都很复杂,你要一个一个去找ID,不得累死,万一找漏了一个,就会功亏一篑了,所以我们要向获取正确的ID路径,就要借助于SDK给我们提供的一个工具--hierarchyviewer.bat.
它的路径在 SDK安装目录\tools\hierarchyviewer.bat, 这是我的安装路径:F:\Android_Studio\Android-SDK\tools\hierarchyviewer.bat.
双击它并打来,我们会看到下面这个显示界面,可能你会觉得奇怪,但请不要着急,稍微等一会儿,它会去自动搜索你的模拟器。
如果它没有搜索到你的模拟器,就会是这种现实状态:(不知道什么原因,我的模拟器在eclipse中获取不到了):
也就是说下面没有任何关于模拟器的信息显示,此时回过头去eclipse中的device查看,发现模拟器也不见了。可能很多人会在此时去选择重启模拟器,但是完全不用,我们可以通过命令行去重新连接。
重新连接模拟器:
打开 开始-->运行-->输入cmd-->回车
在命令行中输入adb devices,点击回车,发现没有任何设备连接,此时就需要我们去重新连接。
在命令行中输入adb connect 127.0.0.1:6555,点击回车,显示connected to 127.0.0.1:6555
然后再次输入adb devices去查看我们的设备列表,就能够识别到了。如下图:
在第一条命令中,127.0.0.1是模拟器的IP地址,6555是端口号,我们可以直接在eclipse-devices窗口中看到的哈~如果使用的是别的模拟器,可以自行查看。很多模拟器是可以直接连接的,但是天天模拟器的连接很麻烦,我也是摸索了很久,才找到这个解决方法。
然后就可以看到我们连接成功后,hierarchyview.bat的界面如下显示:
选中我们的项目,会看到Load View Hierarchy 按钮变为可点击状态,点击该按钮,会出现下面这个界面:
左边这个图中的结构图就是我们当前显示的activity的layout中定义的布局结构图啦~我们可以在左图中的空白区域按住鼠标左键左右拖动来移动图片,也可以通过滚动鼠标来放大缩小图片,当你点击具体的节点时,可以在右边和节点上方看到预览图。并且我们可以很方便的去查看ID,在每一个节点中都会有显示。
接下来,假如说我们要实现一个按钮点击事件,就需要去找到这个按钮的ID,那怎么找呢,首先,我们先找到这个按钮,然后从左图最开始的节点,找出所有带有id值得节点,直到按钮ID所在节点为止,例如,我有一个按钮,id为button_dispatcher,它的路径是:
content->ll_main->linearlayout_side_screensaver->sidebar_fragment->ll_dispatcher->button_dispatcher,因为这个图的根节点是从phoneWindow开始的,我们寻找的时候,只需要从我们的自己的MainActivity加载的层开始寻找就可以了,所以我的路径是从linearlayout_side_screensaver开始的(这里为什么不是从phoneWindow层开始,就要涉及到Android的一个层级结构了,有兴趣的自己去查查哈!这里就不细说了)
好了,不说了,我直接贴代码,还有一个层级结构的图,方便大家比对。
(初来乍到,有很多写的不规范的地方,大家主要看思路就好)
代码如下:
from com.android.monkeyrunner import MonkeyRunner as mrfrom com.android.monkeyrunner import MonkeyDevice from com.android.monkeyrunner import MonkeyImage as mifrom com.android.monkeyrunner.easy import EasyMonkeyDevice, Byfrom com.android.chimpchat.hierarchyviewer import HierarchyViewerfrom com.android.hierarchyviewerlib.models import ViewNodetry: device= mr.waitForConnection()except Exception: print 'device connect to VM failed!!!'try: easyMonkey=EasyMonkeyDevice(device)except Exception: print 'easyMonkey are not available!!!'try: hierachy_view=device.getHierarchyViewer()except Exception: print 'hierachy_view are not available!!!'def returnhierarchyview(): return device.getHierarchyViewer()def returneasyMonkey(): return EasyMonkeyDevice(device)def returnfinviewbyid(idvalue): #hierachy_view=returnhierarchyview() return hierachy_view.findViewById(idvalue)def returnById(idvalue): return By.id(idvalue)def action_touch(widges,widgesname): easyMonkey=returneasyMonkey() print widgesname ,'is available?(True or Faulse)',easyMonkey.visible(widges) if(easyMonkey.visible(widges)): print 'the ---',widgesname,'----was touched' easyMonkey.touch(widges,MonkeyDevice.DOWN_AND_UP) mr.sleep(1) else: return 0 def action_type(widges,value): easyMonkey=returneasyMonkey() easyMonkey.type(widges,value) print 'if ',value,' is available?(True or Faulse) ',easyMonkey.visible(widges) print 'input a test case , value = ',value mr.sleep(1)# test delivery man #admname username#password passworddef testlogin(admname,password): mr.sleep(2) #easyMonkey=returneasyMonkey() #hierachy_view=returnhierarchyview() try: view_node1 = returnfinviewbyid('id/sidebar_fragment') view_node2 = returnfinviewbyid('id/ll_dispatcher') print('touch button delivery man') action1=returnById("id/button_dispatcher") action_touch(action1,'button dispatcher') view_node3 = returnfinviewbyid('id/content_fragment') view_node4=returnfinviewbyid('id/account_num') adm=returnById("id/administrator_number") action_type(adm,admname) passw = returnById("id/password_edittext") action_type(passw,password) action4 = returnById("id/login") action_touch(action4,'button login') print "sleep for 3 seconds!!" mr.sleep(3) except NameError: print 'the id can not be found!!!' #########################################################def getgoods(): easyMonkey=returneasyMonkey() #hierachy_view=returnhierarchyview() layoutview01=returnfinviewbyid('id/linearLayout_body_sreenSaver') view_node3=returnfinviewbyid('id/content_fragment') layoutview01=returnfinviewbyid('id/linearlayout_cabinet_2_10') if layoutview01 is None: layoutview01=returnfinviewbyid('id/linearlayout_cabinet_4_10') layoutview02=returnfinviewbyid('id/linearlayout_cabinet_opendoor_back2') button_back=returnById("id/cabinet_opendoor_back_410") action_touch(button_back,"cabinet_opendoor_back_410") else: linear_openback_view=returnfinviewbyid('id/linearlayout_cabinet_opendoor_back') button_back=returnById("id/cabinet_opendoor_back_210") action_touch(button_back,"cabinet_opendoor_back_210") ##########################################################test the function after login page.def parceldelivery(order,phone): easyMonkey=returneasyMonkey() #hierachy_view=returnhierarchyview() # view_node = returnfinviewbyid('id/content_fragment') dilivePackage=returnById("id/dilivePackage") action_touch(dilivePackage,"dilivePackage") orderId=returnById("id/orderId") textstr = easyMonkey.getText(orderId) if(textstr == ''): action_type(orderId,order) else: empty1=returnById("id/empty") action_touch(empty1,"empty") #easyMonkey.setText(orderId,"") action_type(orderId,order) phoneNum=returnById("id/phoneNum") text=easyMonkey.getText(phoneNum) if(text == ''): action_type(phoneNum,phone) else: #easyMonkey.setText(phoneNum,"") empty2=returnById("id/empty") action_touch(empty2,"empty") action_type(phoneNum,phone) button_next=returnById("id/button_next") action_touch(button_next,"button_next") print "sleep for 6 seconds!!" mr.sleep(6) getgoods() # button_diliv_back = returnById("id/button_diliv_back") # action_touch(button_diliv_back,"button_diliv_back") def takegoods(identifycode): sider_layou=returnfinviewbyid('linearLayout_side_sreenSaver') tackgood_layout=returnfinviewbyid('id/sidebar_fragment') ll_getpackage=returnfinviewbyid('ll_getpackage') action1=returnById("id/button_getpackage") action_touch(action1,'button getpachage') layoutview01=returnfinviewbyid('id/linearLayout_body_sreenSaver') view_node3 = returnfinviewbyid('id/content_fragment') relativeview=returnfinviewbyid('charge_card_number1') edit_getpackage=returnById("id/take_goods_number") action_type(edit_getpackage,identifycode) take_goods_enter=returnById('id/take_goods_enter') action_touch(take_goods_enter,"take_goods_enter") print "sleep for 6 seconds!!" mr.sleep(6) getgoods() ########################################################## if __name__ == '__main__' : import codecs import time time_format='%Y-%m-%d %X' try: codecs.register(lambda name:codecs.lookup('utf-8') if name == 'cp65001' else None) print('APP start to test...') print('start robot main activity') componentName='包名/.MainActivity' device.startActivity(component=componentName) print('MainActivity begin to run') mr.sleep(3) except Exception: print 'this is somehing wrong!!!' #test delivery activity #test case #testlogin('123456','000000') #testlogin('12345678','000000') #testlogin('123','000000') #test parcel delivery #test case #parceldelivery('1234564','15678909878') #parceldelivery('123456','156789098') #parceldelivery('1234','15678909878') #parceldelivery('','') #parceldelivery('','15678909878') #parceldelivery('123456','') try: for i in range(1,10): print '<<<<<<<<<<<<<<<<<<<<<<<<<<','This is the ',i, ' times to run>>>>>>>>>>' print 'the current time is ',time.strftime(time_format,time.localtime()) testlogin('300001','987654') parceldelivery('1098000000001416801','15983629282') takegoods('123456') print '\nthe end time is ',time.strftime(time_format,time.localtime()) print '<<<<<<<<<<<<<<<<<<<<<<<<<<','the End of ',i, ' times>>>>>>>>>>>\n\n' except Exception: print 'this is a exception occur...'
下面是我的页面的一个层级结构:(因为图片太大了,可能有点看不清):
大家可以比对这个图,就大概能理清思路了。
注意:可能有人会注意到我在程序中使用了sleep来休眠几秒,是因为有时候我们会有弹出框来提示信息,如果在弹出框还没有消失的时候,我们监测到的当前界面就是弹出框界面,而不是原来界面,同样会提示找不到id之类的信息,所以一定要休眠,等到弹出框消失之后,再继续运行,就不会报错啦~
三.运行查看结果
首先,打开命令行:开始->运行->cmd
在命令行中将路径切换到你的android SDK的tools目录所在路径,我是为了方便运行,避免输入路径,直接把python文件放在了tools目录下。然后运行下面的命令,以下是我的运行结果:
这个是页面启动,如果你的程序并没有运行,他可以找到你的安装路径,并启动。当然,安装路径要在程序中自己设置,通常,我们可以通过在命令行去查看。
这是测试中的输出,我们可以在模拟器中看到自动化测试的过程,就是这样啦~
- 使用python和android模拟器做android程序的自动化测试
- python + appnium 做android自动化测试
- android studio使用espresso做自动化测试
- 使用Python进行Android自动化测试
- Appium+Robotframework实现Android应用的自动化测试-2:Windows中启动Appium和模拟器
- 用python做自动化测试--对服务器端的自动化测试(2)-发送端Http Client模拟器
- 用python做自动化测试--对服务器端的自动化测试(4)-接收端Http Server模拟器
- 控制Android自动化测试程序的稳定性
- 使用Selenium或appium做 Android自动化测试
- android 自动化测试--robotium使用,可以用来做自动化、单元测试等一系列测试
- Python + Android + Uiautomator自动化测试
- Python + Android + Uiautomator自动化测试
- ATX+Python:Android自动化测试
- Appium+Python:Android自动化测试
- python自动化测试android项目
- 基于android模拟器和脚本录制工具的自动化操作
- Android自动化测试之appium的使用
- Android使用Monkey的自动化测试
- 几个玩具代码(不用main的编程)
- 黑马程序员全力打造高薪IT人才
- 整数规划求解有向图最短路径问题环路解决方法
- Win7驱动安装时的信任列表管理
- 炉石传说-鱼人骑士-斩杀计算器-Android
- 使用python和android模拟器做android程序的自动化测试
- 移位操作
- 实现点击箭头,展示更多text内容
- http://www.jianshu.com/p/cf446be43ae8
- 用js写一个可以拖拽的浮动窗口
- 最小二乘算法之我见(一)
- 自定义环形菜单
- Linux 内核 SCSI IO 子系统分析
- Android ICU data 文件编译