开源测试工具 DreamMultiDevices 框架解析 (一)

陈子昂 · 2019年09月18日 · 最后由 友台 回复于 2019年09月18日 · 1517 次阅读
前言

框架作者是一位上海上市游戏公司测试负责人,陈大猫也是一名游戏产业从业者,通过网络上成为了网友。
在腾讯系 GA 没有更新的 2 年后,网易的 airtest 出了一款游戏自动化的产品,在 MSTC2018 大会上亮相,社区内相关帖子也有不少,也有 qq 群,这块就不介绍了。

关于在 IDE 上使用 个人建议,不推荐的,主要是不能完成组内累积和其他项目复用,可读性不高和比较难维护。
这个论点在网上被反驳过,回应是本身工程思想很强或者开发能力强的人还是建议用工程化去开发,IDE 不一定要 OOP,python 也是多范式的语言,如果只有工程思想的人花点时间学习代码,只会更好不会变差。

不用会代码提供编程计算在现阶段是属于关系自我矛盾的或者只是为了宣传,比如让用户新手引导一路点下去一样顺畅,写多了用户突然发现可以优化,还是改到工程里写吧,然后学习代码,成为自动化高手,然后一门语言到多门语言,走上一条去少林寺的道路。

正文

当然业内也有一批使用者用 airtest 做为底盘的基础上开发,出于种种原因,作者开源了这个 airtest+ 混合 poco+ 性能比脚手架晋升一步的框架属于比较完整的,支持在 airtestIde 以外执行
作者上篇文章 ,框架地址:https://github.com/saint228/DreamMultiDevicesfork 以及参与维护。。其中受益者和赞赏者也可以来点星,关注,

安装方式具体看说明,请自建 pip 虚拟环境,后面会建议作者添加一个 requriements.txt 指定版本的描述文件,然后【 pip install -r requriements.txt】

本文陈大猫和作者商量过,从程序运行顺序做源码解读,也顺带帮助宣传下框架。
【行文规范】
地址是指 github 上面地址,不是 clone 下来查看的。
画外音:自己夹带私货的导读,不包含对框架评论。

1.入口文件

DreamMultiDevices/blob/master/start.py
位置在项目根目录下面

from DreamMultiDevices.core import index
#Index.main()提供启动逻辑功能
#启动前前置行为:
#1.启动adb服务
#2.启动包装了index.main()

画外音:多线程和多进程编程也推荐这个模式,把相关逻辑文件引用链接到入口文件
执行骨干文件

DreamMultiDevices/blob/master/core/index.py
导入类库主要
from multiprocessing import Process,Value #多进程模式 使用了创建多进程模块和共享变量
from DreamMultiDevices.core.MultiAdb import MultiAdb as Madb  #自己封装的adb,Madb是别名

index.main() 函数
1.先获取手机的 device 执行对象 支持多个

Madb().get_devicesList() # 获取 adb devices 列表

画外音:
等同 devices = [devlist [0] for devlist in ADB().devices()],ADB().devices() 由源码提供,列表推导式 devlist [0] 里面内容,第一台链接上的手机。
ADB().devices() 正确返回 是列表内套多个元祖对象 [(手机码, device),(手机码, device)]

Device 应该是用于代码需要到 DreamMultiDevices/blob/master/core/MultiAdb.py 查看

一开始陈大猫以为是典型的访问器和设置器的写法,设置器是通过 ini 文件。

self._devicesList 实例化区域内通过Config.getValue获取属性的写法
self._configPath=self._rootPath+"\config.ini"
self._devicesList = Config.getValue(self._configPath, "deviceslist", ) 
#这2行代码说明了读取ini的文件位置,这块代码不做解读了继续往下。

2.如果没有获得内容实时链接获得一次

if devicesList[0] == "": # 代表 上面第一个元祖里面的第一个位置是 “”,需要再次获取。
作用使用的是 os.popen() 的方式,优点执行失败不会返回错误码,一旦要对错误信息进行过滤处理,就会增加麻烦。

3. line31 对 Config.ini 的防御代码

如果有填写 device 对象拿到,获取到继续往下 。
如果没有填写走到下面一行缓存内,声明是必须必填项目,给予一个状态机 devicesList=None

这里等于 None 会在第 line47 行进行分叉,goto 到 line 86 行,未找到设备,建议是主动断开.

画外音:有互联网朋友说游戏产业真的对状态机(中间变量)特别有偏好,如果做过这块逻辑就知道了,一个大型脚本几百个的,有 100-200 个中间变量不算多了,业务很复杂。

4. 读取状态功能 是否跳过性能测试

同上,通过访问器。
在反序通过相等==“1” 三目表达式拿到布尔对象赋予 skip_performance 对象
画外音:python 有一个 property,但不适合这个地方,三目表达式是好东西,虽然 python 不是编译型语言。

5. 是否需要存储性能数据

这个和上面一样的,前提是先开通上面的。

6. 初始化功能型文件夹

Os.getcwd 拿到运行时路径,拼接到根目录 Report 文件夹。
没有加在 git 里,因为这 3 个目录是放用户数据。用户如果在库外调用,那会生成在执行代码所在的目录。

7.devicesList 上面不为空,继续往下执行

用列表装载进程池,用 for …range 的模式把每个对象取出来后放到 MultiAdb 的实例化里面去
看看实例化的代码作用 关键字 mdevice 初始为 “”,这个时候实例化后就放置了 device 对象。
画外音:py 在内存里面,主要是列表和字典这 2 个,字典因为没有偏移的关系并且在 3.5 还是 3.3 以上支持会更好。

8. madb.get_androidversion() 设置最低版本支持

不满足的手机通过 continue 轮空
通过 adb 反馈的结果拿到当前的安卓版本,这块反馈的是 str,int(version) 在函数内显式转换比在调用时调转更好

9.多进程执行 target=关键函数

上面 8 的另外一个分支或者不被轮空的手机在多进程区域开辟 2 段 int 类型内存 flag 和 fpsflag(方法区往上的共享区域),定义字面值为 0

#取之前的状态机skip_performance,上面有写,通过Config.ini里面预设好的,在载入到类的实例变量内,然后通过get方法访问器反馈出来。  
#P1变量通过Process创建记录性能的进程(进程属性引用的函数名称,args元祖区域传入形参列标参数)  
#List.append()把常见的进程添加到生命周期依然存活的列表.  
#P2变量通过Process创建执行进程,其他类似,创建后添加到进程池内,进程池内长度在1-2.  

通过 for in 的模式 让 start() 就绪区域后执行,然后 join 防止主进程结果后,进入阻塞,等待子进程完成。

10.打印日志,让批量执行的手机屏幕关闭
screenoff=Madb().get_screenoff() 是拿到ini里面的变量
#这里注意setScreenOFF是引用到了其他文件from DreamMultiDevices.tools.ScreenOFF import * 藏到了*里面
DreamMultiDevices/blob/master/tools/ScreenOFF.py

setScreenOFF() 内部先判断执行平台,然后赋值 2 个变量,这 2 个变量用来放不同情况下的可提供 os.popen(cmd 字符串)

os.popen 反馈的结果中做字符串内容拆分 如果取出字符串位置等于 false 包含在 result 内不处理,如果不是,os.popen(触发 26) 相关代码.

Keyevent 可以网上自行查映射关系。下面就是用一个 while 循环去触发上面的行为直到"mScreenOnEarly=false"

在函数内部往所有机器都关闭,最后在外层函数打印设备 xxx 已经关闭。

画外音: 以上服务都是 adb 原生提供的,这个一般使用 adb 的模式,判断是不是闭屏,如果不是 keyevent 锁屏,但这里主要是通过变量设置。

11.中间发生错误的拦截

通过导入类库区域导入的 2 个类库

结果发送邮件(目前暂时屏蔽了)

暂时写到了
DreamMultiDevices/blob/master/core/index.py  94
下篇会跳到enter_processing()逻辑方法内
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 2 条回复 时间 点赞

已在大佬群里,群里氛围特别好,解决了自己很多问题,支持。

试试看看

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