自动化测试中写测试脚本、维护脚本是件苦差事。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)
可以加的参数有:
packageName/ActivityName (例如com.example.demo/.MainActivity)
, 可以有多个。当检测到当前运行的 activity 在这些里面时,会生成图片识别语句,否则默认生成 ui 识别语句。当然后面是可以调整的。这个设置在游戏测试时会有用,因为游戏一般不能用 ui 识别来做,但游戏里面有些渠道登陆支付之类的是可以用 ui 的。运行例子,来简单测试一下我手机上的一个软件 “外汇大富翁”:
$ python -matx record -d test01
连接手机后,运行上述指令启动,启动后,就可以在手机端操作来生成脚本了。
录制结束后,按 Ctrl+C 停止录制,此时会自动开启 web 服务器来调试修改。界面是这个样子的:
目前可以用来忽略某些步骤、修改 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看上面生成的脚本可以看出,目前自动生成的脚本还是有很多缺点的,比如:
d.start_app(...)
后续计划在 web 端增加代码运行调试功能、合并某些操作的功能,有可能的话尝试增加一些逻辑控制以及可以插入额外语句的功能,还有做分辨率无关。
欢迎大家的指导和建议,可以留言或发送到 atx 的gitter中。