Android自动化测试初探

入职两月有余,从之前的android app开发到现在的测试框架开发,工作中遇到很多问题,趁这次机会分享一下。

Android自动化测试目前可借鉴的经验不多,现在采取的方式就是通过java代码对Activity和View进行操作,目前已知的入口是Instrumentation类。

Instrumentation与Activity均位于android.app包下,这个包内还有诸如ActivityManagerNative这种不对App层开放的类,通过查看Android源码发现Activity类中诸如startActivity(Intent intent)这样重要的方法都是通过Instrumentation实现,Instrumentation中也提供了一系列对Activity生命周期控制的方法。以Instrumentation为基础,Android SDK在Junit基础上进行了扩展,提供了AndroidTestCase类及系列子类,其中最重要的一个类是ActivityInstrumentationTestCase2。

基于Instrumentation的测试框架的工作原理SDK中的这张图说明的很清楚了:

研究Android源码发现框架层中有很多对测试有帮助的类、方法都被加上了@hide注解或是声明为private的,无法从app层访问。自然而然我们想到了java的反射机制, java反射允许我们访问这样的类和方法。

在上面的基础上,国外有人开发出了Robotium工具,可以在有app源码或apk的情况下进行自动化黑盒测试。

但是Robotium目前的缺点也很明显,无法对WebView进行操作,这对大量使用WebView的淘宝Android客户端来说无疑是很大的限制。

而且Robotium提供的API是面向过程的,测试代码的可扩展性差。

我们需要一个面向对象的,可对WebView进行操作的自动化测试框架,这就催生了TMTS(Taobao Mobile Test Studio)框架。

TMTS立项时还试图着重解决另一个问题,就是Instrumentation框架下testapp和app运行在一个进程中 ,app crash会导致testapp一并crash。当时和士敦一起研究了Instrumentation、Activity的启动流程,甚至想去研究一下dalvik是如何解析Manifest文件的,最后也没有想到好的方法,收获就是了解了android更底层一些的细节,这个问题现在先搁置了起来。

从测试代码方面来看, Robotium中采用的是actionMethod(View, arg)的方式,TMTS中采用getView(id).actionMethod(arg)的方式,更加符合java的编程习惯。TMTS测试代码的编写也就是分三步,找到View,调用View的相应的action方法,断言。

TMTS框架主要思想就是通过反射机制调用Android框架层API拿到当前Activity的所有View,在此基础上返回需要获得的View对象,对获得的View通过Instrumentation封装一些此View常用的操作,最后返回,这就是TmtsView及其子类。

这种方式缺点也很明显,对每个从android.View继承来的子类,如果其中有特殊的操作,就需要封装出一个对应的TmtsView子类。

还有一个缺点就是目前是通过View在布局文件中声明的id去寻找,这样测试人员在编写代码时需要对app的源码非常熟悉,了解当前操作的view的id是多少,在传递id参数时还有可能写错。之后我们对这个方式进行了一些改进,使用SDK自带的hierarchyviewer工具获得view的id;对每个布局文件进行解析生成java类,这个类中会提供方法返回布局文件中的所有带id的view,经过讨论,最后按view子类型来对一个布局中的view进行归类。

现在测试代码从getView(id).actionMethod(arg)演变成了Layout(layout.class).ViewType().view().actionMethod(arg)的方式,代码虽然变长了,但是出错的可能性大大降低了。

Bug的定位离不开日志,因而日志系统也是一个测试框架重要的组成部分,Android的Log类中提供了一系列的静态方法可以在IDE中打印日志。在TMTS中,提供TmtsLog类,除日志打印外可将日志内容实时保存至SD卡指定目录,在框架代码中的关键部位都加上了这样的日志用来保存异常时的调用栈信息,用户的测试代码中也可以加上对TmtsLog的调用跟踪测试代码执行进度,TmtsLog将为每个测试类保存一份这样的日志文件,同时包含用户的过程日志和框架异常日志,文件名以精确到毫秒的日期加以区分。

项目做到这里远远没有结束,套用屈原的一句话就是路漫漫其修远兮。

后面计划解决的问题有:

  1. 跨进程测试,让testapp和app运行在两个不同的进程中,这是一个大坑。
  2. 稳定性问题,目前框架中有很多地方硬编码Thread.sleep()去等待一个View加载完成,避免对空的View进行操作,或者是对一个view进行set操作后,也需要等待一段时间让操作生效。希望能找到一种回调机制优雅的解决。
  3. 设法捕获Toast消息

后面可能会研究的方向,是通过非java的方式来实现android自动化测试。Android目前已经通过ASE(Android Scripting Environment)支持了多种脚本语言,如phyton,lua,perl等,限于目前的人力还没有时间来研究这一块,相信ASE会给Android自动化开辟一片新天地。

最后谈一点点感悟,老子曾经曰过:“持而盈之,不如其已;揣而锐之,不可长保。金玉满堂,莫之能守;富贵而骄,自遗其咎。”和“重为轻根,静为躁君。”第一句话说有缺陷才是真正的完美,没有一个方案是真正完美的。第二句话说有时候看起来完美的方案,过段时间之后又不适用了,而且不适用的地方很可能就是当初觉得完美的地方,对于软件项目解决方案也是如此。

分享到此结束,敬请期待士敦下次关于WebView方面的分享。

你可能感兴趣的:(自动化测试)