【背景】
移动端app飞速发展后,导致各种自动化框架雨后春笋般的发展。纵观这类框架都在声称对于控件的操作是很牛逼的,深入分析后可以看出它们最终会回归到UI基本的坐标点操作。
于是,app自动化测试工程师UI自动化进阶路线:初识各种自动化框架-》编写自动化脚本-》自动化平台化,支持用户脚本录制回放-》持续集成-》玩烂了(case覆盖率越高自动化收益越低、数据问题、产品迭代带来的维护成本)
作为一个app自动化测试的小白,尝试提出一个新的思路:从“运行时”角度尝试自动化。
【解决的问题】
1.传统Ui自动化录制的人力成本-很难录制完美的执行脚本
2.脚本兼容问题-安卓碎片化严重和程序开发的框架性导致的id丢失和不对应的问题
3.一个机型上录制的脚本,换个机型?
4.各种UI级别自动化的诟病。
【技术探究】
一、安卓的事件分发机制:
Android事件 点击、双击、拖拽、滑动、移动、触摸和多点触控
事件的动作组成 down 按下事件,所有的动作必须都是从down事件开始 move 移动事件 up 手指离开事件,一般也代表事件完成
事件的传递 屏幕硬件捕捉到事件 —> 系统 —> 应用 —> activity —> viewgroup*(多层嵌套) —> view(最终的view)
事件的处理方法 dispatchTouchEvent “是否”分发,事件分发方法,activity、viewgroup、View中都有 onInterceptEvent “是否”拦截,事件拦截方法,只有viewgroup中有该方法,用来拦截事件,view是事件分发的终端,所以不需要拦截事件,而activity是用与用户进行交互的,拦截了事件就没意思了 onTouchEvent “是否”消耗,事件处理方法,用来处理事件
ViewGroup的相关事件有三个: onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent。 View的相关事件只有两个:dispatchTouchEvent、onTouchEvent。
事件分发流程图 分发的是down事件,down事件的分发是为了寻找一个可以处理完整事件的控件,down被处理move和up也就被处理了
注:此事件分发图是不包括拦截的
带有拦截(onInterceptEvent)的事件分发,返回true表示拦截,false表示不拦截。拦截的意思就是强制停止向下分发,此时该控件将要判断自身是否能处理该事件,如果处理不了就继续向上返回,返回让上一级处理,如果该控件可以处理该事件则事件被消耗,事件结束。
总结:这就是事件机制,其实可以用递归的思想来理解,递归函数是dispatchTouchEvent(控件),递归体是循环遍历控件的孩子控件,调用dispatchTouchEvent(孩子控件)方法,递归出口有以下几种,①控件为终端控件,没有孩子控件;②onTouchEvent方法返回true,事件被处理了,此时dispatchTouchEvent方法也返回true;③onInterceptEvent方法返回true,事件被拦截。
二、安卓的事件监听机制
Android事件处理包括两个部分:Android事件处理机制(基本)和Android消息传递机制(进阶)。前者包含三种处理方式,即基于监听的事件处理、基于回调的事件处理、直接绑定到标签;后者包含两种处理方式,即Handler消息传递、异步任务处理。
注:图片来自于 裂缝中的阳光JDG
三、安卓的RUNTIME
从上图看安卓的框架组成,仅仅看出一个安卓模块的组成,我们做个简单的划分:其核心是安卓虚拟机,其余为其lib依赖文件,再往上framework和applocations层是使用java语言开发的事件预处理机制。我们看一个事件在执行时安卓做了什么:
安卓的运行时其实就是java的运行时!
安卓的运行时其实就是java的运行时!
安卓的运行时其实就是java的运行时!
重要的话说三遍。
【脑洞大开】
我们去想一个问题:
安卓的自动化测试进行录制回放时,我们实际做了什么?
脚本录制-》脚本回放-》框架点击坐标点
接着看自动化框架接下来做了什么?
想了想也没做啥,框架点击了坐标,接下来就是安卓自己触发了操作。
那么安卓做了什么?
事件分发-》触发监听-》从监听程序段入口执行代码-》java和jvm
那么,如果自动化框架可以直接从事件分发时或者触发监听时或者事件入口直接触发事件呢,和现有的自动化效果有何区别?
嗯..... 应该执行的时候没有点击效果,事件会继续完美执行吧?
如果自动化录制时直接拦截这些事件呢?
嗯..... 入参和函数地址无差异化~
【接下来....】
如何实现事件的拦截和事件的回放?
1.代码替换。
xpose框架怎么完成某些app的监听与代执行的?
通过安卓虚拟机和框架层的连接控制jar包hook住各个安卓包的class文件,找到对应的类。
2.反转注入与aop
如果把java主流开发框架spring的思路运用在这里?
貌似spring在开发之初没有几行代码。