上回说到,在Android自动化测试时,通过反射机制,我们能获得页面的所有控件。来看一个简单的应用例子:
ArrayList<View> views = getAllViews(); for(View view : views) { Log.d("Views On Activity:", view.getClass().getName()); }
这样在LogCat里我们就可以打印出所有的View了:
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.LinearLayout
03-27 22:24:52.369: D/Views On Activity:(2123): com.android.internal.widget.ActionBarContainer
03-27 22:24:52.369: D/Views On Activity:(2123): com.android.internal.widget.ActionBarView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.LinearLayout
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.ImageView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.LinearLayout
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.TextView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.TextView
03-27 22:24:52.369: D/Views On Activity:(2123): com.android.internal.widget.ActionBarView$HomeView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.ImageView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.ImageView
03-27 22:24:52.369: D/Views On Activity:(2123): com.android.internal.view.menu.ActionMenuView
03-27 22:24:52.369: D/Views On Activity:(2123): com.android.internal.widget.ActionBarContextView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.FrameLayout
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.RelativeLayout
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.RelativeLayout
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.TextView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.TextView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.ImageView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.ImageView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.RelativeLayout
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.TextView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.TextView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.TextView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.TextView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.TextView
03-27 22:24:52.369: D/Views On Activity:(2123): android.widget.Button
03-27 22:24:52.369: D/Views On Activity:(2123): com.android.internal.policy.impl.PhoneWindow$DecorView
我们看到这里罗列了所有的控件,有Layout, TextView, Button 等等。而获得了这些控件,对我们有什么用呢?
比如:
下面分享一些我们项目中用到的关于这些操作的典型片断:
public void clickOnView(int id) { View view = solo.getView(id); if(view != null) { solo.clickOnView(view); } }
public boolean isViewGone(int id, long timeout) { final long endtime = SystemClock.uptimeMillis() + timeout; while(SystemClock.uptimeMillis() < endtime) { if(solo.getView(id).hasFocusable()) { solo.sleep(10); } else { return true; } } return false; }
public Bitmap getSourceIcon() { BitmapDrawable drawable = (BitmapDrawable) sourceImageView.getDrawable(); return drawable.getBitmap(); }
这里的sourceImageView变量,就是一个ImageView的实例。
为了方便,我们在项目中使用了Robotium框架,但是如果追本溯源的话,我们不禁要问:
我们知道Robotium框架是基于Instrumentation,并且市面上大多数的Android测试框架都是基于Instrumentation的,而Instrumentation就是我们做自动化的基石,一层层的跟进Robotium的Click方法,我们会看到最终它是调用Instrumentation的:
来实现Click操作。
For Example: Solo.clickOnView(View view) 会调用 clicker.clickOnScreen(view) 跟进去我们会看到下面的代码:
public void clickOnScreen(float x, float y) { long downTime = SystemClock.uptimeMillis(); long eventTime = SystemClock.uptimeMillis(); MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0); MotionEvent event2 = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0); try{ inst.sendPointerSync(event); inst.sendPointerSync(event2); sleeper.sleep(MINISLEEP); }catch(SecurityException e){ Assert.assertTrue("Click can not be completed!", false); } }
这样我们就明白了,原来在Android automation testing, Click的操作是这么实现的!
要是我们自己来写Android自动化测试框架,我们也可以提供这样一个方法嘛~