ATX [atx 系列] android 脚本录制

wuxc · 2016年08月19日 · 最后由 codeskyblue 回复于 2017年03月20日 · 3730 次阅读

简介

自动化测试中写测试脚本、维护脚本是件苦差事。atx 中已有辅助写脚本的 gui 工具和 webide,最近又增加了一个录制生成脚本的辅助工具,这个工具使用起来也比较简单,启动后直接在手机上操作即可,停止录制后,会开启一个 web 服务器来修改完善生成的脚本。

atx 使用了图像识别来做自动化测试,对 android 平台也集成了 uiautomator 可以用 ui 识别。因此这个工具可以生成图像识别语句 +ui 识别语句的混合脚本,而且可以通过提供的 web 服务器很方便地在这两种语句间切换。

使用

先来看一下使用方法吧。

首先需要安装 atx 库

$ pip install atx

工具启动同 atx 其他辅助工具类似,用-h 可以看一下帮助信息

$ python -m atx record -h

usage: __main__.py record [-h] [-d WORKDIR] [-a NONUI_ACTIVITIES]

optional arguments:
  -h, --help            show this help message and exit
  -d WORKDIR, --workdir WORKDIR
                        workdir where case & frame files are saved. (default:.)
  -a NONUI_ACTIVITIES, --nonui-activity NONUI_ACTIVITIES
                        nonui-activities for which the recorder will analyze
                        screen image instead of uixml. (default: None)

可以加的参数有:

  • -d 设置工作目录,默认为当前目录,不过最好设一个值,会自动在当前目录下创建子目录
  • -a 设置非 ui 识别的 activity,格式为 packageName/ActivityName (例如com.example.demo/.MainActivity), 可以有多个。当检测到当前运行的 activity 在这些里面时,会生成图片识别语句,否则默认生成 ui 识别语句。当然后面是可以调整的。这个设置在游戏测试时会有用,因为游戏一般不能用 ui 识别来做,但游戏里面有些渠道登陆支付之类的是可以用 ui 的。

运行例子,来简单测试一下我手机上的一个软件 “外汇大富翁”:

$ python -matx record -d test01

连接手机后,运行上述指令启动,启动后,就可以在手机端操作来生成脚本了。

录制结束后,按 Ctrl+C 停止录制,此时会自动开启 web 服务器来调试修改。界面是这个样子的:
web.png
目前可以用来忽略某些步骤、修改 ui 选择或截图区域。

录制过程中的每一步操作的手机状态信息存放在工作目录下的 frames 中,生成的脚本存放在工作目录下的 case 中。
要执行脚本的话,先把手机恢复到初始状态,到 case 目录中执行python script.py就能看到脚本执行了。

生成的脚本样例如下

#-*- encoding: utf-8 -*-
# Generated by recorder.

import time

def test(d):
    d.keyevent("KEYCODE_MENU")
    d(className=u"android.widget.ImageView").click(timeout=1700)
    d.keyevent("KEYCODE_HOME")
    d.keyevent("KEYCODE_MENU")
    d(className=u"android.widget.ImageView").click(timeout=900)
    d(className=u"android.widget.FrameLayout").click(timeout=1200)
    d.swipe(961, 832, 503, 829, 10)
    time.sleep(1.76)
    d.swipe(950, 1231, 515, 1227, 10)
    time.sleep(0.57)
    d.swipe(982, 1273, 423, 1303, 10)
    time.sleep(0.59)
    d.swipe(962, 1193, 452, 1221, 10)
    time.sleep(0.62)
    d.swipe(991, 1223, 361, 1251, 10)
    time.sleep(0.83)
    d.swipe(965, 1234, 377, 1233, 10)
    time.sleep(0.66)
    d(className=u"android.widget.FrameLayout", description=u"外汇大富翁").click(timeout=1500)
    d(text=u"英雄榜").click(timeout=4700)
    d(text=u"账户").click(timeout=1600)
    d(text=u"市场").click(timeout=1600)
    d(text=u"我的").click(timeout=1800)
    d(text=u"自选").click(timeout=1800)
    d(className=u"android.widget.ImageView", resourceId=u"com.netease.forextrader:id/search").click(timeout=2200)
    d.swipe(577, 1620, 648, 986, 10)
    time.sleep(1.96)
    d(text=u"确定").click(timeout=2600)
    objs = d(className=u"android.widget.TextView", resourceId=u"com.netease.forextrader:id/ratio")
    if objs.wait.exists(timeout=3400):
        objs[1].click()
    d(text=u"1天").click(timeout=2600)
    d(text=u"1周").click(timeout=700)
    d(text=u"1月").click(timeout=600)
    d(text=u"3月").click(timeout=800)
    d(text=u"1年").click(timeout=600)
    d(className=u"android.widget.ImageView").click(timeout=2000)
    d(text=u"英雄榜").click(timeout=3800)
    d(text=u"1周").click(timeout=2300)
    d(text=u"1月").click(timeout=1200)
    d(text=u"累计排名").click(timeout=1400)
    d(text=u"常规赛").click(timeout=1500)
    d(text=u"挑战赛").click(timeout=1600)
    d(text=u"账户").click(timeout=7900)

if __name__ == "__main__":
   import atx
   d = atx.connect()
   test(d)

原理

原理也比较简单,主要有以下几点:

  • adb getevent -lt实现用户输入的 hook
  • 自定义的一套简单的手势解析
  • 用 minicap 截屏
  • 用 uiautomator 的 dump 来获取 uixml,并解析 layout 来定位 ui 元素
  • 用户手势识别出来后,会根据发生的时间将当时的手机状态保存起来,录制结束后分析所有操作,根据手势和状态来生成代码
  • 用 tornado 实现的简单的服务器,前端用 vuejs 搭建

说明及后续计划

看上面生成的脚本可以看出,目前自动生成的脚本还是有很多缺点的,比如:

  • 一些繁琐的操作需要手动去合并掉。比如前面的几个 swipe 和点击 “外汇大富翁” 图标的操作,可以合并成d.start_app(...)
  • 没有逻辑结构,例如循环、条件判断等。这些还是离不开测试人员手动添加的
  • 由于 uiautomator 的 dump 时间限制,操作过快时导致 ui 布局文件不能及时更新,因此自动生成的 ui selector 可能有错误
  • 没有统一的清理接口,需要手动清理。
  • 部分脚本不是分辨率无关

后续计划在 web 端增加代码运行调试功能、合并某些操作的功能,有可能的话尝试增加一些逻辑控制以及可以插入额外语句的功能,还有做分辨率无关。

欢迎大家的指导和建议,可以留言或发送到 atx 的gitter中。

参考

共收到 17 条回复 时间 点赞

希望功能越来越强大,持续关注~。😀

这里为啥能显示手机,你用的是什么浏览器?

—— 来自 TesterHome 官方 安卓客户端

悲剧了只支持 2.7 啊有一个包,不过的确是好东西👍。

@ wuxc,cmd 运行 python -m atx record -h 后,提示:
C:\Python27\python.exe: DLL load failed: %1 不是有效的 Win32 应用程序。; 'atx' is a package and cannot be direc
tly executed

wuxc #6 · 2016年09月12日 Author

#5 楼 @super_c 是不是 cv2 没装?试下 import cv2 有没有错?

#6 楼 @wuxc 的确是的,我装了之后可以运行了,谢谢

为什么我录制完按 ctrl+c 报一堆错,web 页面都看不到图片,然后点击 run 也不会执行。。。。不懂怎么玩,求教。。。。

关注

wuxc #10 · 2016年10月08日 Author

#8 楼 @snail 可以贴一下报错内容么?

您好,我用的 mac 安装的 android-sdk-macosx,
运行 python -matx record -d test01 时,报了 2 个 error,手机操作的时候,日志都是显示 Unknown code ABS_MT_TOUCH_MINOR
报错如下:
(1)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/atx/strutils.py", line 27, in decode
raise UnicodeDecodeError(','.join(encodings), "", 0, len(s or ''), "string: '%s'" % repr(s)) TypeError: object of type 'exceptions.EnvironmentError' has no len()
(2)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/atx/adbkit/mixins.py", line 136, in open_minicap_stream
w, h, r = map(int, m.groups())
AttributeError: 'NoneType' object has no attribute 'groups'

赞一个

怎么提示不包含这个命令?
python -m atx record -h
usage: main.py [-h] [-s SERIAL] [-H HOST] [-P PORT]
{tcpproxy,gui,minicap,apkparse,monkey,install,screen,screenca
p,screenrecord,web,run,version,info,doctor}
main.py: error: invalid choice: 'record' (choose from u'tcpproxy', u'gui', u
'minicap', u'apkparse', u'monkey', u'install', u'screen', u'screencap', u'screen
record', u'web', u'run', u'version', u'info', u'doctor')

jack-github 回复

考虑到种种原因,该功能已关闭

codeskyblue 回复

什么时候能再次开放?

jack-github 回复

这是个好问题,我也不知道

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册