简易自动化测试架构搭建

简易自动化测试架构搭建

  • 前言
  • 硬件准备
  • 软件准备
    • 操作系统
    • Python
    • STF
  • 代码编写
  • 一些踩过的坑

前言

前一段时间,用python+夜神实现了基于模拟器的自动化测试。链接见:
https://blog.csdn.net/saint_228/article/details/84889017

最近想把自动化在真机上实现。所以捣鼓了几天,弄了个简易版测试架构,开销不多,效果不错,在此分享给大家。

2019-5-21 增补:项目实例代码下载地址: https://download.csdn.net/download/saint_228/11169391

2019-5-30 增补:CSDN上更新版本不便,源码放到git :https://github.com/saint228/DreamMultiDevices

硬件准备

我们公司提供了5部测试手机,但同一台PC机不可能同时接入这么多设备。所以,采购一个带电源的USBHub是必须的开销。某宝上百来块入手了一个。简易自动化测试架构搭建_第1张图片
建议再买个机架,看起来更专业一点。合计开销不到200。
简易自动化测试架构搭建_第2张图片

软件准备

我期望的自动化测试能在每天的dailybuild之后自动进行apk的下载、安装、运行测试脚本并发送邮件,同时还能在网页上实时观察测试进展。综合这些需求,我采用的是Linux+STF+Pyhon的方式。如果不需要使用到STF,那在Windows平台上也是可以行得通的。

操作系统

使用的是CentOS7,网上安装教程一大堆,这里不赘述。

Python

CentOS自带的Python是2.7版本,不建议使用。

[qatest@127 ~]$ python
Python 2.7.5 (default, Apr 11 2018, 07:36:10) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux2
Type "help", "copyright", "credits" or "license" for more information.

默认的Python千万别动,很多其他模块会依赖于它。
我们需要重新安装一个Python3的版本,目前的Python3的最高版本是3.7,但考虑到与Poco的兼容,建议下载Python3.6。

[root@127 qatest]# yum install python36

(PS:实际上我首先一开始并未下载3.6,而是直接下载的3.7版本,但使用CentOS默认源下载的Poco、Airtest等其他库对3.7并不兼容。如果手动更换源,应该也是可以用3.7版本的。)
之后记得给python3.6设一个环境变量,方便之后直接调用。

[root@127 qatest]# python36
Python 3.6.6 (default, Jan 26 2019, 16:53:05) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux
Type "help", "copyright", "credits" or "license" for more information.

然后装pip

[root@127 qatest]# yum install python36-pip

pip装好以后用pip去安装脚本会用到的若干库。特别注意一点,python3.6并不与最新的airtest以及pocoui兼容。要安装特定版本。

[root@127 qatest]# pip3.6 install airtest==1.0.24
[root@127 qatest]# pip3.6 install pocoui==1.0.70
[root@127 qatest]# pip install multiprocessing
...

我的整个脚本里还用到了traceback(抓取异常)、smtplib(邮件发送)、xlrd/xlwt(Excel表格处理)等库,酌情添加。

STF

STF是开源的一个远程网页调试手机的框架。
简易自动化测试架构搭建_第3张图片
其本身的安装非常麻烦,推荐使用docker容器来安装。
首先安装docker。

[root@127 qatest]# yum install -y yum-utils   device-mapper-persistent-data lvm2 && yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo -y&&yum  -y install docker-ce-18.06.3.ce-3.el7&&systemctl start docker  &&systemctl status  docker

输入docker version,看到客户端和服务端的信息,就说明安装成功。

[root@127 qatest]# docker version
Client:
 Version:           18.06.3-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        d7080c1
 Built:             Wed Feb 20 02:26:51 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.3-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       d7080c1
  Built:            Wed Feb 20 02:28:17 2019
  OS/Arch:          linux/amd64
  Experimental:     false

docker安装好以后再pull一下stf需要的几个镜像

sudo docker pull openstf/stf:latest # STF镜像
sudo docker pull rethinkdb:latest # rethinkdb 镜像
sudo docker pull openstf/ambassador:latest
sudo docker pull nginx # nginx 镜像

然后加载容器

docker run -d --name rethinkdb -v /srv/rethinkdb:/data --net host rethinkdb rethinkdb --bind all --cache-size 8192 --http-port 8090
docker run -d --name stf --net host openstf/stf stf local --public-ip 127.0.0.1

本来stf的推荐流程里还要装一个adb,但adb在airtest里已经自带,所以就没必要重复安装了。直接adb start-server即可。如果无法直接执行,就添加一下环境变量。
然后启动STF所需的rethinkdb、adb以及STF本身,注意rethinkdb和adb需要在STF启动之前启动。

docker run -d --name rethinkdb -v /srv/rethinkdb:/data --net host rethinkdb rethinkdb --bind all --cache-size 8192 --http-port 8090
docker run -d --name stf --net host openstf/stf stf local --public-ip 127.0.0.1

我这里ip设定的本地访问,需要根据实际情况修改。然后在浏览器输入对应ip:7100即可访问。
简易自动化测试架构搭建_第4张图片
简易自动化测试架构搭建_第5张图片

代码编写

测试的脚本主要是调用python的airtest库来进行控件操作。
为了同步多部手机同时运作,这里需要使用多进程来编写脚本。
(PS:python的多线程无法满足我的需求,一开始我的脚本用多线程来实现,结果是每部手机逐次运行脚本,并不能达到同步运行的效果)

#将设备id存入deviceslist
deviceslist    = cc8c4f82,6c176579,P4M0215107001638,99fa1f38,
packName = 包名

if __name__ == '__main__':
    try:
        pool = multiprocessing.Pool(processes = len(deviceslist))
        startTime = time.localtime(time.time())
        #根据设备数创建相应进程
        for i in range(0, len(deviceslist)):
            results.append(pool.apply_async(Main, (i, startTime, )))
        pool.close()
        pool.join()
    except AirtestError as ae:
		print(startTime, "System", "进程池 发生错误:\n" )

然后在Main函数里,进行测试脚本的调用

def Main(processNo, startTime):
	#进程与设备是一一对应关系
    devices = deviceslist[processNo]
	print(startTime, "进程: " + str(processNo) + " 设备号:" + devices)
	#调用PushApk2Device函数,推送apk到手机
    PushApk2Devices(devices, packName, startTime)
    time.sleep(3)
    print(startTime, "System", devices + " 脚本开始")
    testResult = RunTestCase(devices, startTime) # 开始调用脚本

中间调用到的PushApk2Device函数的作用是将待测试的apk推送到设备上,相关代码如下:

def PushApk2Devices( devices, packName, startTime):
srcpath=GetPath()
    try:
        print(startTime, "System", devices + " 开始安装新版本")
        #由于设备均未root,所以采用-r方式覆盖安装,可以绕过安装apk时的各个权限确认
        result = os.system("adb -s " + devices + " install -r " + srcpath)
        print(startTime, "System", devices + " 安装新版本: " + str(result))
    except Exception as e:
        print(startTime, "System", devices + " 安装新包 发生错误:\n" )
        sys.exit()

#GetPath方法获取源包的路径。由于我们项目dailybuild的服务器是Windows系统,所以在linux上取包需要提前将对应路径挂载到/mnt/apkPath 目录下:
file_path = "/mnt/apkPath/"
def GetPath(): 
    dir_list = os.listdir(file_path)
    #getmtime方法按时间顺序,获取目录最新一个文件
    filelist = sorted(dir_list, key=lambda x: os.path.getmtime(os.path.join(file_path, x)))
    lastest_release = filelist[-1]
    #拼接路径与文件
    srcpath = os.path.join(file_path, lastest_release)
    return srcpath

另一个RunTestCase则是开始进行实际测试的函数

def RunTestCase(devices, startTime):
    try:
        print(startTime, devices, "创建设备连接")
        #手动指定连接,这一步很重要
        connect_device("Android:///" + devices)
        print(startTime, devices, "设备连接成功")
        time.sleep(15)
        #初始化设备
        auto_setup(__file__)
        print(startTime, devices, "启动App")
        start_app(packName, activity = None)
       print(startTime, devices, "App启动完成")
        time.sleep(15)
        #初始化poco
        poco = UnityPoco()
        print(startTime, devices, "初始化设备完成")
    except AirtestError as ae:
        printstartTime, devices, "初始化设备 Airtest发生错误:\n" )
        

之后就可以自由自在地运行自己写的各种测试脚本了。
脚本执行时,也可以通过STF,远程观察测试程序实时的运行情况。

一些踩过的坑

  1. pip install须指定特定版本,各个库的最新版本之间不一定兼容。
  2. 使用adb install 需加-r 参数,覆盖安装时不需要重新申请各种权限。对root手机,可以用adb shell pm install的命令直接安装。
  3. airtest/夜神/Python&各品牌手机各有各的adb,尽量保持彼此同版本进行通信。
  4. adb不能冲突。如果测试主机上同时存在多个adb进程,建议全部清掉,重启adb服务。
  5. 先使用手机连接电脑adb成功以后,再在电脑上打开夜神模拟器,adb会被夜神接管,所有手机重新弹usb连接确认框,故手机和模拟器无法同时跑。
  6. adb连接都存在一定活跃期,活跃期过后使用虽然adb devices命令显示设备正常连接,但是使用时会有各种各样的连接问题。要么另外写一个心跳,要么每次执行测试前手动kill-start server。
  7. python的多线程无法满足要求,须使用多进程。各进程之间需要异步处理apply_async()。开出多少子进程就必须回收多少子进程,回收全部子进程后才会执行主进程之后的代码。
  8. 数据线质量需要靠谱,不佳的数据线会导致各种连接问题,且不易排查。
  9. “远程主机断开连接”,可能是连接尚未完成时就执行了后续的poco代码。(adb断开连接,USB断开连接等其他连接问题也会导致该报错)
  10. “jsondecodeerror”是poco连接andorid5的版本时会出的一个问题,同一段代码同样的环境,在安卓4和7的虚拟机上ok,在安卓5上就报错。无法解决。
  11. “UnicodeEncodeError”,可能使用了python2编写的代码或库,导致解析失败。
  12. 用airtest提供的connect_device()函数来对各个进程指定连接的设备,不然不同进程的代码执行时会“串线”
  13. 设备初始化的流程:连接设备->auto_setup(file)->启动APP->poco=UnityPoco()
  14. 屏幕截图必须先存到设备本地再发送至测试主机,直接存到主机会导致文件损坏
  15. devices not ready错误,顺序检查:手机开发者模式是否打开->手机usb调试是否打开->数据线是否连接->adb devices能否查询到设备->是否有多个环境的adb冲突

liunx:
16. liunx系统中许多程序需要python2.7支持。安装python3后需要将python3设置为默认,并在安装pip后将其指向python3
17. 部分系统(比如:ubnutu)pip安装的python库会被安置到dist-packages,而python的第三方库路径在site-packages中,需要通过配置.pth文件重定向读取路径
18. 注意adb工具、Log文件夹等路径的权限
19. 定时任务crontab文件的配置完成后需要等待3-5分钟,cron服务才会自动加载配置

手机配置:
20. 小米系统的手机需要登录小米账户后在开发者选项中开启“USB调试(安全设置)”,不然无法进行模拟点击测操作

你可能感兴趣的:(poco,STFServer,python)