入职两月有余,从之前的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反射允许我们访问这样的类和方法。
在上面的基础上,国外有人开发出了robot/" target="_blank" >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)的方式,代码虽然变长了,但是出错的可能性大大降低了。