标签:
只能是浅析,不敢说什么解析,对比网上大神的详细分析,只能从整体去分析相关的东西,什么时候才能深入算法层面呢?
在分析源码之前,我们先来看看robotium给我们提供了什么样的类。
在对整体有了一个认知之后,我们从solo类入口,因为solo是robotium的入口类,也是最重要的类,先来看看构造方法:
private Solo(Config config, Instrumentation instrumentation, Activity activity) {
if(config.commandLogging){
Log.d(config.commandLoggingTag, "Solo("+config+", "+instrumentation+", "+activity+")");
}
this.config = (config == null) ? new Config(): config;
this.instrumentation = instrumentation;
this.sleeper = new Sleeper();
this.sender = new Sender(instrumentation, sleeper);
this.activityUtils = new ActivityUtils(config, instrumentation, activity, sleeper);
this.viewFetcher = new ViewFetcher(instrumentation, sleeper);
this.screenshotTaker = new ScreenshotTaker(config, instrumentation, activityUtils, viewFetcher, sleeper);
this.dialogUtils = new DialogUtils(instrumentation, activityUtils, viewFetcher, sleeper);
this.webUtils = new WebUtils(config, instrumentation,viewFetcher, sleeper);
this.scroller = new Scroller(config, instrumentation, viewFetcher, sleeper);
this.searcher = new Searcher(viewFetcher, webUtils, scroller, sleeper);
this.waiter = new Waiter(instrumentation, activityUtils, viewFetcher, searcher,scroller, sleeper);
this.getter = new Getter(instrumentation, activityUtils, waiter);
this.clicker = new Clicker(activityUtils, viewFetcher,sender, instrumentation, sleeper, waiter, webUtils, dialogUtils);
this.setter = new Setter(activityUtils, getter, clicker, waiter);
this.asserter = new Asserter(activityUtils, waiter);
this.checker = new Checker(viewFetcher, waiter);
this.zoomer = new Zoomer(instrumentation);
this.swiper = new Swiper(instrumentation);
this.tapper = new Tapper(instrumentation);
this.illustrator = new Illustrator(instrumentation);
this.rotator = new Rotator(instrumentation);
this.presser = new Presser(viewFetcher, clicker, instrumentation, sleeper, waiter, dialogUtils);
this.textEnterer = new TextEnterer(instrumentation, clicker, dialogUtils);
this.systemUtils = new SystemUtils(instrumentation);
initialize();
}
排除了重载的构造方法,可以看到初始化solo对象的时候会传入三个参数, Config对象
Instrumentation对象,activity对象。后两个就不多说了,在学习instrumentation框架的时候已经知道了instrumentation对象是在运行之前注入到被测应用中去的,而activity重要性也不多说啦,于是就剩下Config,这个对象是运行robotium的一些设置参数,我们看看有什么:
public static class Config {
/**
* The timeout length of the get, is, set, assert, enter and click methods. Default length is 10 000 milliseconds.
*/
public int timeout_small = 10000;
/**
* The timeout length of the waitFor methods. Default length is 20 000 milliseconds.
*/
public int timeout_large = 20000;
/**
* The screenshot save path. Default save path is /sdcard/Robotium-Screenshots/.
*/
public String screenshotSavePath = Environment.getExternalStorageDirectory() + "/Robotium-Screenshots/";
/**
* The screenshot file type, JPEG or PNG. Use ScreenshotFileType.JPEG or ScreenshotFileType.PNG. Default file type is JPEG.
*/
public ScreenshotFileType screenshotFileType = ScreenshotFileType.JPEG;
/**
* Set to true if the get, is, set, enter, type and click methods should scroll. Default value is true.
*/
public boolean shouldScroll = true;
/**
* Set to true if JavaScript should be used to click WebElements. Default value is false.
*/
public boolean useJavaScriptToClickWebElements = false;
/**
* The screenshot file type, JPEG or PNG.
*
* @author Renas Reda, renas.reda@robotium.com
*
*/
public enum ScreenshotFileType {
JPEG, PNG
}
/**
* Set to true if Activity tracking should be enabled. Default value is true.
*/
public boolean trackActivities = true;
/**
* Set the web frame to be used by Robotium. Default value is document.
*/
public String webFrame = "document";
/**
* Set to true if logging should be enabled. Default value is false.
*/
public boolean commandLogging = false;
/**
* The command logging tag. Default value is "Robotium".
*/
public String commandLoggingTag = "Robotium";
}
之后就是一些类的实例化,initialize()方法则是超时时间初始化。
完成初始化的分析之后继续研究solo这个类,通读接口之后人为分成下面几个类别:
webview相关就没有看了,因为没有用到
Asserter:
Robotium给我们新增的两个assert方法,当然都是在Asserter类定义的:
assertCurrentActivity和assertMemoryNotLow
assertCurrentActivity:检查当前的activity是否是我期望的activity,本质上是取出当前activity的实例然后getclassName,最后通过Assert.assertEquals方法判断的
Activity activity = activityUtils.getCurrentActivity();
if(activity != null){
Assert.assertEquals(message, name, activity.getClass().getSimpleName());
assertMemoryNotLow:检查当前系统是否内存不足,充足那么通过,原理是通过
ActivityManager.MemoryInfo对象来检查
ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
((ActivityManager)activityUtils.getCurrentActivity().getSystemService("activity")).getMemoryInfo(mi);
Checker:
这个类是用来判断某个view的状态的,我们举例其中一个方法:
这是判断按钮可不可以点击,waiter方法是筛选条件作用,并转化为view,最后调用的其实是widget自身的属性状态
再举例其他的方法
Clicker:
点击方法一直是自动化的重点对象,直接看clickOnScreen
因为根据原理,查找到期望的view之后,最终都会转为xy坐标,并调用上面这个方法去点击屏幕。而clickOnScreen的本质还是调用了instrumentation的sendPointSync方法,实现注入点事件。
当然还是有两个不是调用点击屏幕的方法
clickLongOnTextAndPress
clickOnActionBarItem/clickOnActionBarHomeButton
Scroller:
滚动的类,包括两个操作drag和一些可以滚动的操作
Drag执行的操作是DOWN–>MOVE–>UP,调用的还是sendPointSync方法
至于列表的滚动操作,通过runOnMainSync的堵塞方法,在主线程直接调用view的
setSelection方法直接滚到第N行的。
Searcher:
负责查找和定位控件的类,这个类主要是根据文字获取文字控件的,然后返回一个view,主要看searchFor这个方法。
那么这个方法的原理是通过viewFetcher.getCurrentViews(viewClass, true)方法获取所有控件,然后遍历所有控件,通过正则匹配控件,当匹配到则返回view,也就是上面的返回值了,再者,有一点要注意,查找会提供自动滚滚动的操作,只需要传入参数设置为true即可,比较方便。
TextEnterer:
Robotium支持两种文本注入,api也已经告诉了我们
前者就是我们单元测试经常用的setText方法,后者则是调用了instrumentation的sendStringSync方法注入,而sendStringSync会把string分成一个一个字符,然后循环一个个调用sendKeySync方法,所以调用第二种方法注入你可以看到输入轨迹
ViewFetcher:
这里面封装了所有查找view的方法。
那么通过上面可以知道是通过windowManager的相关方法取得里面的DecorViews,也就是控件树,剩下的方法都是如何去筛选DecorViews里面相关的内容,就不多说啦。
总结:
那么一路下来呢,可以发现这么个规律
1.查找控件都是通过取得window下的DecorViews然后迭代对比得到的
2.查找控件之后view都会转换为xy坐标,最终调用instru的sendPointSync方法点击屏幕
标签:
原文地址:http://blog.csdn.net/cloud_huan/article/details/51354833