All Projects → xiaoyaojjian → AutomatorX

xiaoyaojjian / AutomatorX

Licence: Apache-2.0 License
Make iOS and Android test automated which based on opencv.

Programming Languages

python
139335 projects - #7 most used programming language
javascript
184084 projects - #8 most used programming language
HTML
75241 projects
go
31211 projects - #10 most used programming language
Protocol Buffer
295 projects
shell
77523 projects

logo

AutomatorX (atx) (中文版)

Build Status Documentation Status PyPI PyPI

简介

该项目是为了让手机应用的一些常规测试可以自动化起来,让测试人员摆脱那些枯燥的重复性工作。 基于OpenCV的图像识别技术,有点类似于SikuliX(这东西挺好用的,只是没说要支持手机端)

This project is to make mobile test automated, free people who are boring of repeated job. AutomatorX is a python library base on python-opencv and a lot of outstanding python libs.

ATX is short for AutomatorX

If you are new to atx, it better to start from Quick start tutorial or just view API documentation link

Discuss (讨论群)

面向游戏行业测试人员,当然也开放给国际友人(PS:中文不知道他们看得懂不)

  • Chat room Gitter

PS: 并没有QQ, 因为我们公司上不了QQ

  • 网易内部用户目前请直接联系 hzsunshx

Features

  1. 完全的黑盒测试框架,无需知道项目代码,非侵入式
  2. 可以很好的支持安卓手机的测试,包括安卓模拟器
  3. 支持iOS手机的测试
  4. 支持Windows应用的测试
  5. 对于游戏测试,可以使用图像缩放的方法适应不同分辨率的手机

历史起源

该项目重构于过去写过一个项目 https://github.com/netease/airtest, 因原有代码冗余太严重,维护成本太高,于是就用ATX取代之(Develop from 2016-02-25)。

新版有哪些新的功能呢?

与原版主要变化

  • 简化安装方式,只需要安装opencv以及通过pip安装atx 无其他依赖
  • 支持原生UI元素的查找和点击
  • 截图方式从原有缓慢的adb截图,改成默认uiautomator截图,可选minicap截图(1080x1920手机截图平均耗时0.2s)
  • 优化图像的自动缩放算法,以便同样的脚本可以适应不同的机器
  • 支持Watch用法,可持续监控界面,当某个元素出现时执行特定操作
  • 截图客户端从网页服务器变成了python-Tkinter写的客户端 使用python -matx gui启动
  • 支持dir(dev) 查看元素已有的方法(-_-! 之前代码写的不好,并不支持)
  • 更稳定的依赖库控制,与travis持续集成,可在代码更新后自动发布到pypi
  • 移除性能监控功能(目前性能测试使用第三方工具 腾讯GT)
  • 图像匹配默认使用模版匹配,将SIFT匹配改为可选

更多More

Dependency

  1. python2.7
  2. opencv2.4
  3. Android4.1+

Installation

  1. 首先安装opencv(>=2.4 && <3.0)到你的电脑上

    windows推荐直接通过pip安装,

    # For Win32
    pip install http://o8oookdsx.qnssl.com/opencv_python-2.4.12-cp27-none-win32.whl
    # For AMD64
    pip install http://o8oookdsx.qnssl.com/opencv_python-2.4.12-cp27-none-win_amd64.whl
    

    如果pip安装遇到问题,也可以把相应的numpy和opencv下载下来。然后在本地安装 备用下载地址,安装方法很简单,例如 pip install opencv??.whl, pip最好版本高一点(>=8.1.0),避免出错。

    如果是Macbook,安装方法要比想象中的简单,然而耗时也比想象中的要长, 先安装brew, 之后

    brew install python pillow opencv
    

    Linux暂时先不写了,折腾过的人可以提个PR补充下。

  2. Install atx with pip

    为了编码的时候能少敲一点字母, pip中软件包的名字简化成了 atx

    因为目前代码的更新比较快,如果希望使用新功能的话,推荐安装开发版(目前也强烈推荐使用开发版) For the develop version, (maybe not stable), Sync with github master code

    pip install --upgrade --pre atx
    

    稳定版的发布频率大约为2周一次. Stable version updated about every two weeks.

    pip install --upgrade atx
    

    Sometime https://pypi.python.org may not stable, it is also possible to install from source. (need git installed)

    pip install -U git+https://github.com/codeskyblue/AutomatorX.git
    
  3. Other dependencies (eg: ADB, Xcode)

  4. Show atx version

    python -matx version
    

    Remember the atx version in case if you want to rollback.

  5. Install ATX Assistant into you phone (Only android)

    To make sure device connected, use command adb devices

    Install via command line

    python -m atx install atx-assistant

    Or download and install https://o8oookdsx.qnssl.com/atx-assistant-1.0.0.apk

    This App provided ATX input method, Keep screen wake and some other good stuff. Recommend all user to install it.

    目前该输入法需要手工启动,该输入法为ATX提供命令行的中文输入方法

    adb shell ime set com.netease.atx.assistant/.ime.Utf7ImeService
    

Some may still failed the installation. There are some ways which may help you.

  1. Uninstall your python, and reinstall from https://python.org

  2. Mac user may found install numpy error

    Reference: http://blog.csdn.net/hqzxsc2006/article/details/51602654

  3. Windows user may found install pyyaml failed.

    Just download the pyyaml wheel file and install with pip. http://www.lfd.uci.edu/~gohlke/pythonlibs/#pyyaml

Quick start (Android and iOS)

  1. Connect an device

    • Android

      Android phone (sdk>=4.1) to PC

      Open terminal, execute adb devices, make sure you see your device.

       $ adb devices
       List of devices attached
       EP7333W7XB      device

      创建一个python文件 test.py, 内容如下

       # coding: utf-8
       import atx
      
       d = atx.connect() # 如果多个手机连接电脑,则需要填入对应的设备号
       d.screenshot('screen.png') # 截图

      运行 python test.py

    • iOS

      WDA运行完之后,准备好DEVICE_URL, 如 http://localhost:8100

      python代码可以这样写

       # coding: utf-8
       import atx
      
       d = atx.connect('http://localhost:8100', platform='ios') # platform也可以不指定
       print d.status()
  2. Take screenshot

    • Android: python -m atx gui
    • iOS: python -m atx gui --serial http://localhost:8100

    更多命令可以通过python -m atx gui --help 查看。如果屏幕超过了整个屏幕可以通过调小 --scale 来调整

    鼠标左键拖拽选择一个按钮或者图标, 按下Save Cropped截图保存退出. (按下Refresh可以重新刷新屏幕)

    gui

    PS: 这里其实有个好的IDE截图的最好了,现在是用Tkinter做的,比较简洁,但是可以跨平台,效果也还可以

    截图后的文件另存为 button.png, test.py 最后增加一行 d.click_image('button.png')

    重新运行 python test.py, 此时差不多可以看到代码可以点击那个按钮了

  3. 更多

    可以使用的接口还有很多,请接着往下看

Examples

ATX毕竟是一个python库,给出代码的例子可能更好理解一些

接口可以参考sphinx自动生成文档 Documentation on ReadTheDocs

在Github也记录了部分关键的API接口说明

文档可以等下在看,先看一些例子

  • Initial android device connect (Only Android)

     import atx
    
     d = atx.connect()

    通过设置相应的环境变量也可以设置连接参数,用来方便持续集成

    目前支持4个环境变量

     ATX_ADB_SERIALNO
     ATX_ADB_HOST
     ATX_ADB_PORT
     ATX_PLATFORM  默认是 android
     $ python -c 'import atx; atx.connect("EFF153")'
    
     # 等价写法
     $ export ATX_ADB_SERIALNO="EFF153"
     $ python -c 'import atx; atx.connect()'
  • App start and stop

     package_name = 'com.example.game'
    
     d.stop_app(package_name)
    
     # d.stop_app(package_name, clear=True) # stop and remove app data (only Android)
     d.start_app(package_name)
  • Execute shell command (Only Android)

     d.adb_cmd(['pull', '/data/local/tmp/hi.txt']) # default timeout 30s, use timeout=None to set unlimited time
     d.adb_shell(['uptime'])
     
     # forward device port to localhost
     # same as 
     # adb forward tcp:$(randomPort) tcp:10080
     # Expect: (host, port)
     print d.forward(10080)
    
     print d.wlan_ip # 获取手机的Wlan IP
    
     print d.current_app() # 获取当前运行应用的package name和activity以及运行的pid
     # Expect: AppInfo(package='com.miui.mihome2', activity='com.android.launcher2.Launcher', pid=634)
  • 图片查找与点击

     # find image position
     if d.exists('button.png'): # 判断截图是否在屏幕中出现, 反馈查找到的坐标
     	print 'founded'
    
     # take screenshot
     d.screenshot('screen.1920x1080.png') # Save screenshot as file
    
     # click position
     d.click(50, 100) # 模拟点击 x, y
    
     # long click
     d.long_click(50, 100) # only works on android for now
  • click_image函数

     # click image, if "button.png" not found, exception will be raise.
     d.click_image("button.png")
    
     # add description (also used for report generate)
     d.click_image("button.png", desc="I love click")
    
     # click image, if "button.png" not found, will return None
     d.click_image("button.png", safe=True)
    
     # click image with long click
     d.click_image("button.png", action='long_click')
    
     # 不等待的图片点击, 如果图片不存在直接返回None
     d.click_nowait('button.png')
    
     # 文件名添加截图手机的分辨率, 脚本运行在其他分辨率的手机上时可以自动适应
     d.click_image("button.1920x1080.png")
     # 等价于
     d.click_image(atx.Pattern('button.png', rsl=(1080, 1920)))
    
     # 文件名中添加偏移量, 格式为 <L|R><number><T|B><number>.png
     # 其中 L: Left, R: Right, T: Top, B: Bottom
     # number为百分比
     # 所以 R20T50代表,点击为止从图片中心向右偏移20%并且向上偏移50%
     d.click_image("button.R20T50.png")
     # same as
     d.click_image("button.png", offset=(0.2, -0.5))
    
     # Full example
     d.click_image("button.png", 
     	offset=(0.2, 0.5), 
     	action="long_click", 
     	safe=True, 
     	desc="I love click", 
     	method='template', 
     	threshold=0.8)
    
     # if image not show in 10s, ImageNotFoundError will raised
     try:
     	d.click_image('button.png', timeout=10.0)
     except atx.ImageNotFoundError:
     	print('Image not found')
    
     # 在特定的区域内查找匹配的图像(IDE暂时还不支持如此高级的操作)
     nd = d.region(atx.Bounds(50, 50, 180, 300))
     print nd.match('folder.png')
  • 原生UI操作

    里面的API是直接通过继承的方式支持的。

     # click by UI component
     d(text='Enter').click()
     d(text='Enter').sibling(className='android.widget.ImageView').click()
    
     # swipe from (sx, sy) to (ex, ey)
     d.swipe(sx, sy, ex, ey)
     # swipe from (sx, sy) to (ex, ey) with 10 steps
     d.swipe(sx, sy, ex, ey, steps=10)
  • 文本的输入 (only Android)

     d.type("hello world")
     d.type("atx", enter=True) # perform enter after input
  • Common settings

     # 配置截图图片的手机分辨率
     d.resolution = (1920, 1080)
     print d.resolution
     # expect output: (1080, 1920) 实际获取到的值会把小的放在前面
    
     # this is default (first check minicap and then check uiautomator)
     d.screenshot_method = atx.SCREENSHOT_METHOD_AUTO # 默认
     # d.screenshot_method = atx.SCREENSHOT_METHOD_UIAUTOMATOR # 可选
     # d.screenshot_method = atx.SCREENSHOT_METHOD_MINICAP # 可选
    
     d.image_match_method = atx.IMAGE_MATCH_METHOD_TMPL # 模版匹配, 默认
     # d.image_match_method = atx.IMAGE_MATCH_METHOD_SIFT # 特征点匹配, 可选
    
     # d.image_match_threshold = 0.8 # 默认(模版匹配相似度)
    
     d.rotation = None # default auto detect, 这个配置一下比较好,自动识别有时候识别不出来
     # 0: home key bottom(normal)
     # 1: home key right
     # 2: home key top
     # 3: home key left
    
     # 图片路径查找(实验性功能)
     d.image_path = ['.'] # 默认
     
     # 主要用在希望代码和图片放在不同目录的情况, 如代码结构
     # /--
     #   |-- test.py
     #   |-- images/
     #          |- photo1.png
     #          `- photo2.png
     #
     
     # test.py 中的关键性代码
     d.image_path = ['.', 'images']
     d.click_image('photo1.png')
     d.click_image('photo2.png')
  • 监控事件 (这个挺好用的)

    watch是一个内部循环,对于on函数中的所有出现的图片进行监控,如果发现吻合的,就执行后续的操作,直到timeout时间到。

    下面的这个例子,效果为 当出现notification.png就点击confirm.png图片,只有检查的顺序,并没有执行的顺序。需要注意的是需要在timeout超时之前,执行quit函数

     # watcher, trigger when screenshot is called
     def foo(event):
     	print 'It happens', event
     	d.click(*event.pos)
    
     timeout = 50.0 # 50s
     with d.watch(timeout=timeout) as w:
     	w.on('enter-game.png').click()
     	w.on('notification.png').on('npc.png').click('confirm.png')
     	w.on('inside.png').quit().quit()
     	w.on_ui(text='Login').quit() # UI Component
     	w.on('outside.png').do(foo)
    
     # will not raise errors(TODO: not working in latest version)
     # 'enter game' is just a name which will seen in debug log
     with d.watch('enter game', timeout, raise_errors=False) as w:
     	w.on('output.png').click()
  • events函数调用事件

     def my_listener(event):
     	print 'out:', event
    
     d.add_listener(my_listener, atx.EVENT_SCREENSHOT)
     d.screenshot()
    
     # expect output:
     # out: HookEvent(flag=8, args=(), kwargs={})

ATX Extentions

该部分属于atx的扩展插件实现的功能

插件说明

  • HTML Report

    利用此插件可以在ATX自动化跑完之后,自动生成可以HTML报告,详细记录每一步的执行情况

  • Performance record (For Android)

    性能测试直接使用了腾讯开源的GT

    PS: 刚写好没多久,你只能在最新的开发版中看到。有可能以后还会修改。

    使用方法

    1. 首先需要去腾讯GT的主页上,将GT安装到手机上

      http://gt.qq.com

    2. 代码中引入GT扩展

      import atx
      from atx.ext.gt import GT
      
      
      d = atx.connect()
      
      gt = GT(d)
      gt.start_test('com.netease.my') # start test
      # ... do click touch test ...
      gt.stop_and_save()
    3. 运行完测试后,代码会保存到/sdcard/GT/GW/+包名(com.netease.my)目录下,直接使用adb pull下载下来并解析

      $ adb pull /sdcard/GT/GW/com.netease.my/
      

    该部分代码位于 atx/ext/gt.py, 这部分代码目前在我看来,易用性一般般,希望使用者能根据具体情况,进行修改,如果是修改具有通用性,欢迎提交PR,我们会负责Review代码。

Command line tools

为了方便测试以及开发,atx封装了很多的命令行工具,功能包含端口转发,包解析,安装,截图等等。

针对iOS的命令行工具

需要加上前缀 python -m atx.ios

  1. developer (因为部分链接还在内网,所以目前只能在网易内部用)

    将iOS设置成开发者模式,需要手机连接上电脑。(仅在windows测试过)

    依赖: iTunes, iMobileDevice

    python -m atx.ios developer
    
  2. screencap

    截图功能(使用前设备需要设置成开发者模式)

    python -m atx.ios screencap -o screen.png
    

针对Android的命令行工具

运行命令行需要加上python -m atx 前缀,如启动gui的命令是python -m atx gui,命令行的帮助查看方法

python -m atx --help
  1. gui

    简单版的GUI,主要用于截图

  2. minicap

    用于安装minicap到手机上

  3. tcpproxy

    简单的tcp转发工具,目前用在了模拟器的转发上面,对于海马玩模拟器,使用方法

    • 在一台运行这海马玩的电脑上运行 python -matx tcpproxy
    • 记录下机器的IP地址,比如 10.0.0.1
    • 在另外一台机器上运行 adb connect 10.0.0.1 来远程连接
  4. apkparse

    用于解析apk的包名和activity,使用方法

    $ python -matx apkparse demo.apk
    {
    	"main_activity": "com.example.demo.activity.Main",
    	"package_name": "com.example.demo"
    }
    
  5. install (仅限apk)

    支持从URL,以及本地路径安装应用,支持文件推送到手机时显示进度

    $ python -matx install example.apk
    2016-04-26 16:33:52.370 INFO  [install:  93] APK package name: com.netease.example
    2016-04-26 16:33:52.370 INFO  [install:  94] APK main activity: com.netease.example.MainActivity
    2016-04-26 16:33:52.371 INFO  [install:  96] Push file to android device
    100% |===========================================| 5.88M/5.88M [4.89M/s]
    2016-04-26 16:33:57.521 INFO  [install:  99] Install ..., will take a few seconds
    2016-04-26 16:34:08.179 INFO  [install: 101] Done
    
    $ python -matx install --start example.apk
    # Start app after installed.
    
  6. screencap 拥有超越adb shell screencap的速度以及兼容性,使用了PIL库,输出的格式根据文件的扩展名的自动确定

    $ python -m atx screencap -o screen.png

    如果需要复制到剪贴板,需要在额外安装一个库 pip install pypiwin32

  7. screenrecord (仅限android)

    录制视频功能,需要预先安装minicap

  8. info

    显示手机重用信息,输出格式是JSON

    $ python -m atx info

FAQ

  1. 如果连接远程机器上的安卓设备

    远程机器上使用如下命令启动命令

    adb kill-server
    adb -P 5037 -a nodaemon server
    # or: adb -P 5037 -a fork-server server
    

    连接时指定远程机器的IP和端口号就好了

  2. 如何一个脚本可以适应不同的机器(针对于手机游戏)

    市面上大部分的手机都是 16:9 还有一部分是 4:3,5:3,8:5 其他比例的似乎寥寥。而游戏中元素的大小,在屏幕变化的时候,也会等比例的去缩放。16:9到4:3的缩放比例似乎也有规律可循,暂时不研究啦。

    W/H Display
    16/9 540x960, 720x1280, 1080x1920, 1440x2560
    8/5 800x1280, 1200x1920, 1600x2560
    5/3 1152x1920, 1080x1800
    4/3 1536x2048

    所以通常只需要找个分辨率高点的设备,然后截个图。同样宽高比的手机就可以一次拿下。

    d.resolution = (1080, 1920)
    

    设置完后,当遇到其他分辨率的手机,就会自动去缩放。因为ATX主要针对游戏用户,横屏的时候,缩放是根据Y轴缩放的,竖排则根据X轴。可能有点抽象,理解不了也没关系

  3. 是否可以在模拟器上运行自动测试

    测试后,发现是可以的。我直接用了当前市场上最流行的海马玩 版本0.9.0 Beta 安装完之后使用 adb connect 127.0.0.1:26944 连接上,之后的操作就跟普通的手机一样了。注: 根据海马玩版本的不同,端口可能也不一定一样

    海马玩监听的端口是本机的26944,如果需要测试脚本运行在远程,用tcp转发到0.0.0.0就好了。方法有很多,可以用自带的程序 python -matx tcpproxy 或者直接参考目录下的 scripts/simple-tcp-proxy.py 用代码实现

    很多模拟器的引擎是VirutualBox,其实还可以通过VirtualBox的接口来截图,这种方法更快一点,不过看说明安装似乎很复杂,试验了下也没成功,若是有人搞定了,可以分享下

  4. minicap是什么, 如何安装?

    minicap是openstf开源项目中的一个子项目,用于手机快速的截图. 连接手机到电脑上之后,简单的安装方法 python -matx minicap 注意:请不要在模拟器上尝试

  5. 遇到 IOError: RPC server not started!

    卸载已有的应用,重新运行测试

    adb uninstall com.github.uiautomator
    adb uninstall com.github.uiautomator.test
    
  6. 卸载

    adb uninstall com.github.uiautomator
    adb uninstall com.github.uiautomator.test
    
    adb shell rm /data/local/tmp/minicap
    adb shell rm /data/local/tmp/minicap.so
    
  7. 解决输入法遇到的问题

    可以专门为自动化开发的Utf7Ime的输入法, 源码地址

    启动方法

    python -m atx install atx-assistant
    adb shell ime enable com.netease.atx.assistant/.ime.Utf7ImeService
    adb shell ime set com.netease.atx.assistant/.ime.Utf7ImeService

    关闭方法

    adb shell ime disable com.netease.atx.assistant/.ime.Utf7ImeService
    

代码导读

connect 函数负责根据平台返回相应的类(AndroidDevice or IOSDevice)

图像识别依赖于另一个库 aircv, 虽然这个库还不怎么稳定,也还凑合能用吧

每个平台相关的库都放到了 目录 atx/device下,公用的方法在atx/device/device_mixin.py里实现。第三方扩展位于atx/ext目录下。

相关的项目

  1. 基于opencv的图像识别库 https://github.com/netease/aircv

  2. 感谢作者 https://github.com/xiaocong 提供的uiautomator的python封装,相关项目已经fork到了

  3. Android input method https://github.com/macacajs/android-unicode

  4. SikuliX http://sikulix-2014.readthedocs.org/en/latest/index.html

  5. Blockly https://github.com/codeskyblue/blockly

Articles

  1. 让adb install显示进度
  2. Android 屏幕同步和录制工具
  3. 安卓手机的快速截图

Developer dashboards

  1. Platform Versions, Screen Size, Open GL Version http://developer.android.com/intl/zh-cn/about/dashboards/index.html

Contribution

如何才能让软件变的更好,这其中也一定需要你的参与才行,发现问题去在github提个issue, 一定会有相应的开发人员看到并处理的。文档有错误的话,直接提Issue,或者提PR都可以。 由于我平常使用该项目的概率并不怎么高,所有不少问题即使存在我也不会发现,请养成看到问题提Issue的习惯,所有的Issue我都会去处理的,即使当时处理不了,等技术成熟了,我还是会处理。但是如果不提交Issue,说不定我真的会忘掉。

BTW: 有开发能力的也可以先跟开发者讨论下想贡献的内容,并提相应的PR由开发人员审核。

License

This project is under the Apache 2.0 License. See the LICENSE file for the full license text.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].