移动端测试_UIAutomator
Robotium 基于Instrumentation测试框架。国内外使用的比较多,
优点:
1.资料相对较多
2.通过Instrumentation注入被测进程,与被测进程运行在同一进程空间,能够方便的识别被测应用中的被测对象,并对这些对象进行操作。
缺点:
1.与被测进程运行在同一进程空间,由于安卓的进程隔离机制,则会被系统隔离在其他进程之外,无法跨进程操作任何对象。
解决方法:
自行编写服务,基于AIDL或编写socket与monkeyServer进行通信,在robotium测试脚本中调用接口方法来间接实现跨进程操作等,实现相对复杂
UIAutomator 是一个测试的java库,包含创建UI测试的各种api和执行自动化测试的引擎
优点:
1.接口丰富、易用、可支持所有android事件操作
2.可通过断言和截图验证正确性、非常适合UI测试。
3.测试框架则可解决跨进程操作的问题。
4.可通过安卓自带UIAutomator viewer获取应用控件信息
注:如果连接多个设备需要指定ANDROID_SERIAL环境变量来说明对哪个设备进行截屏。设置方法:windows系统,在控制台输入set ANDROID_SERIAL=,设备的序列号可以通过adb devices命令进行查看。
案例设计
以计算器应用为例,介绍具体操作步骤:
(1)启动要测试的app应用(计算器)
(2)使用usb先将手机连接至电脑,安装usb驱动,打开开发者选项、usb调试
(3)运行uiautomatorviewer批处理文件,并截取手机屏幕信息。
(4)根据用例设计,找到对应元素的属性信息,(找出按键1,2,+,=的相关信息)
(5)应用AS、Eclipse、UI automator、ant等工具设计单元测试用例,编译项目
(6)将生产的jar包发到手机设备上,运行测试用例并分析测试结果
AS应用
UiAutomator提供了两种工具来支持UI自动化测试:uiautomatorviewer:用来分析UI控件的图形界面工具,位于SDK目录下的tools文件夹中。uiautomator:一个java库,提供执行自动化测试的各种API。
配置
(1)在app根目录的build.gradle文件中加入依赖:
// AS默认配置,如果如果没有记得加上
androidTestCompile(‘com.android.support.test.espresso:espresso-core:2.2.2’, {
exclude group: ‘com.android.support’, module: ‘support-annotations’})
androidTestCompile ‘com.android.support.test.uiautomator:uiautomator-v18:2.1.2’
注意:uiautomator库支持的最低版本为API 18,所有开发环境的minSdkVersion可设置为18.
(2)在build.gradle文件中配置配置testInstrumentationRunner为AndroidJunitRunner:
defaultConfig {
…
// 这个AS会为我们默认配置,如果没有记得加上
testInstrumentationRunner “android.support.test.runner.AndroidJUnitRunner”
}
(3)补充
dependencies中依赖方式详解
compile 参与编译,并且会打包到debug/release apk中。
testCompile 只参与单元测试编译,不会打包到debug/release apk包中,不需要设备支持。
androidTestCompile 只参与UI测试编译,不会打包到debug/release apk包中,需要设备支持。
Provided 只参与编译,不会打包到debug/release apk中。
APK 不参与编译,只会打包到debug/release apk中。
Debug compile 只参与debug编译,只会打包到debug apk中
Release compile 只参与release编译,只会打包到release apk中。
案例编写及运行
(1)在AS中新建Android工程,在androidTest目录下,自定义继承自UiAutomatorTestCase的测试类
(2)自定义以test开头命名的方法,实现具体的测试步骤
(3)右击自定义类,运行测试案例或者右击各个方法运行单个案例
关键类
在创建项目时引入uiautomator.jar文件(位于android-sdk/platforms/android-X目录下),可以使用UI Automator提供的API类模拟用户动作获取UI界面上的组件元素。Uiautomator API包含关键类可以用于捕获和操控待测安卓应用的UI组件元素。
UIAutomatorTestCase类
UiAutomatorTestCase类继承自Junit3中的TestCase类,并在其setUp() 、tearDown() 、getParams() 函数中。每个测试用例类都需要继承自UiAutomatorTestCase,以实现测试环境的setup,teardown等功能。其中主要是用Bundle实现Android Activity之间的通讯。在UiAutomatorTestCase,还加入了getUiDevice()等方法以实现在测试的任意地方均可调用UiDevice()。
UIDevice类
UiDevice代表设备状态。可以调用UIDevice类实例的方法来检查不同属性的状态,例如当前屏幕方向及屏幕尺寸;可以用来执行设备级的操作,例如强制设备横、竖屏、按home按钮、菜单键等
UIAutomator常用操作
按home键 UiDevice.getInstance().pressHome() 或getUIDevice().pressHome();
按‘a’键 UiDevice.getInstance.pressKeyCode(KeyEvent.KEYCODE_A)
按‘A’键 UiDevice.getInstance().pressKeyCode(KeyEvent.KEYCODE_A,1)
获取屏幕高度 int height=UiDevice.getInstance().getDisplayHeight();
获取屏幕宽度 int width=UIDevice.getInstance().getDisplayWidth();
点击(100,200) UiDevice.getInstance().click(100,200);
点(100,100)滑动至(100,500) device.swipe(100,100,100,500,5)
步长为5ms,步长越长,速度越慢
点(100,100)拖曳至(100,500) Device.drag(100,100,100,500,5)
步长为5ms,步长越长,速度越慢
获取屏幕旋转角度 Int rotation=UiDevice.getInstance().getDisplayRotation();
返回0对应0度,返回1对应90度,返回2对应180度,返回3对应270度
判断是否亮屏 Boolean status=UiDevice.getInstance().isScreenOn();
灭屏 UiDevice.getInstance().sleep();
唤醒 UiDevice.getInstance().wakeUp();
保存手机截屏 UiDevice.getInstance().takeScreenshot(new File(“/sdcard/mytest.png”));
定义超时时间为15S UiDevice.getInstance().click(100,200);
UiDevice.getInstance().waitForIdle(15000);
在15S后才调出点击处的应用则报错,停止运行,否则不提示任何信息。
获取当前界面包名 String packageName=UiDevice.getInstance().getCurrentPackageName();
打开通知栏 UiDevice.getInstance().openNotification();
打开快速设置 UiDevice.getInstance().dumpWindowHierarchy(“test.xml”);
常用按键及其描述功能
pressHome() 模拟按home键
pressBack() 模拟按返回键
pressDpadCenter() 模拟按轨迹球中点按键
pressDpadDown() 模拟按轨迹球向下按键
pressDpadLeft() 模拟按轨迹球向左按键
pressDpadRight() 模拟按轨迹球向右按键
pressDpadUp() 模拟按轨迹球向上按键
pressDelete() 模拟按删除键
presEnter() 模拟按确认键
pressMenu() 模拟按菜单键
pressRecentApps() 模拟按最近使用程序
pressSearch 模拟按搜索键
META_key及其状态值列表
MetaState值 激活状态
0 META_key,例如ALT、SHIFT、CAPS_LOCK未被激活
1 SHIFT或CAPS_LOCK被激活时
2 ALT被激活
3 ALT、SHIFT或CAPS_LOCK同时被激活时
UiSelector类
UiSelector代表一个搜索UI控件的条件,可以在当前界面上查询和获取特定元素的句柄。如果找到多于一个的匹配元素,则返回布局层次结构上的第一个匹配元素作为目标界面对象。如果没有找到匹配的界面组件元素,则抛出异常UiAutomatorObjectNotFoundException。在构建一个UiSelector对象时,可以使用多个属性组合来缩小查询范围。
构建以“微”开头的
UiSelector对象wx UiSelector wx=new UiSelector().textStartsWith(“微”);
// 以设定的条件创建一个对象实例,并赋值给obj对象
UiObject obj=new UiObject(wx);
// 调用obj对象的单击事件,打开微信
Obj.click();
构建含“微”文本的
UiSelector对象wx UiSelector wx=new UiSelector().textContains(“微”)
使用class和text两个属性来设置过滤条件,其括号内为属性值。 UiSelector wx=new UiSelector().className(“android.widget.TextView”).text(“微信”);
构建一个UiSelector对象,通过focusable(可获得焦点)和class属性来进行过滤 UiSelector wx=new UiSelector().focusable(true).
className(“android.widget.CheckBox”);
UiObject obj=new UiObject(wx);
Obj.click();
使用UiSelector类搜索UI控件进行条件设定时会用到的方法,可以通过输入UiSelector wx=new UiSelector()在弹出的提示框中进行选择。
Text();
textMatches(String regex);
textContains();
textStartsWith();
className();
classNameMatches(String regex);
className(Class type);
description();
descriptionMatches(String regex);
descriptionStartsWith();
descriptionContains();
packageName();
PackageNameMatches(String regex);
Enabled();
Focused();
Focusable();
Scrollable();
Selected();
Checked();
Clickable();
longClickable();
childSelector().
UiObject类
UiObject可代表页面的任意元素,通过UiDevice的findObject(UiSelector)方法获取UiObject实例,各种属性定位通过UiSelector来完成。获取到UiObject实例后,就可以对UI控件进行相关的操作。
常用API
clickAndWaitForNewWindow() 点击该元素,并且等待新窗口的展示完毕。这一过程是Android UI Testing框架支持的,不需要额外的控制等待时间。
clickTopLeft() 点击控件元素左上角
longClickBottomRight(), 点击控件右下角
getText() 获取UiObject实例所关联控件的文本
getContentDescription() 获取UiObject实例所关联控件的内容描述
getVisibleBounds()
getPackageName() 可以用来明确是否打开了目标测试应用
setText() 设置所关联控件的输入框,例如,在短信应用中输入电话号码和短信内容
UiSelector edit=
new UiSelector().className(“android.widget.EditText”).instance();
UiObject obj=new UiObject(edit);
Obj.setText(“13588888888”)
UiSelector edit1=
new UiSelector().className(“android.widget.EditText”).instance()
UiObject obj1=new UiObject(edit);
obj1.setText(“hi”);
obj1.clearText();
obj1.setText(“hello”);
getText() 获取控件文本信息,例如,获得屏幕下方应用的文本信息
UiSelector view=new UiSelector().
className(“android.view.View”).instance(4);
UiObject obj=new UiObject(view);
Int count = obj.getChildCount();
for(int j=0; j<count; j++){
UiObject child=obj.getChild(new UiSelector().index(j));
System.out.printIn(child.getText());
}
clearTextField() 清空所关联控件的输入框
waitForExists() 用来操纵相关等待或验证
click() 点击某一控件,例如,
UiSelector qq=new UiSelector().text(” QQ”); // 查询文本为QQ的元素对象
UiObject obj=new UiSelector(qq); // 创建此类型的UiObject元素
Obj.click() // 点击qq
dragTo(UiObject obj,long step) UiSelector qq=new UiSelector().text(“QQ”);
UiObject obj=new UiObject(qq);
UiSelector calc=new UiSelector().text(“计算器”)
UiObject obj1=new UiObject(calc);
Obj.dragTo(Obj1,40); //拖曳qq图标至计算器图标位置
exists() UiSelector view=new UiSelector().className(“android.view.View”).instance(2);
UiObject obj=new UiObject(view);
If(obj.exists()) System.out.printIn(“对象存在!”);
else System.out.printIn(“对象不存在”);
UiCollection类
UiCollection继承自UiObject类,用于枚举一个容器用户界面元素。UiCollection类提供了一些方法获取容器内的子元素对象。使用UICollection类时,通常先按照一定条件枚举出容器内所有符合条件的子元素,再从符合条件的子元素中设定一定的条件从而定位到需要查找的界面元素。
UiCollection一般与UiSelector连用,其构造函数也要求提供Uiselector,UiCollection(UiSelector selector)
常用方法
getChildByDescription() 通过描述信息过滤获取要查找的对象
调用形式:UiCollection 对象+ “.”+ getChildByDescription(childPattern,text);
其中,childPattern为一个UiSelector类型的参数,用于查找出所有符合条件的子元素,text可以指定描述、文本或实例条件
getChildByInstance() 通过实例过滤获取要查找的对象
调用形式:UiCollection 对象+ “.”+ getChildByInstance(childPattern,instance);
getChildByText() 通过文本过滤获取要查找的对象
调用形式:UiCollection 对象+ “.”+ getChildByText(childPattern,text);
getChildCount() 获取子元素个数,例如,
UiCollection u = new UiCollection(new UiSelector().
className(“android.view.View”).instance(4));
// 获得包含子对象元素个数的信息
int count = u.getChildCount(new UiSelector().
className(“android.widget.TextView”));
for(int i=0;i<u.getChildCount();i++){ // 循环取得每一个子对象
UiObject obj=u.getChild(newUiSelector().
className(“android.widget.TextView”).index(i));
assertEquals(true,obj.exists()); // 使用断言判断每一个对象是否存在
obj.click(); // 执行各个对象的单击操纵
UiDevice.getInstance().pressBack(); // 按回退键,回到主界面
Sleep(1000); // 等待1S
}
UiWatcher类
UiWatcher类用于处理脚本执行过程中遇到的异常情况。比如在执行脚本中突然来电,会打断正在执行脚本的正常执行步骤,可以通过UiWatcher类来监听处理这种情况。测试框架无法找到一个匹配对象时,UiSelector()会自动调用此处理程序方法。如果超时未找到匹配项,Ui Automator框架调用checkCondition()方法查找设备上的所有已经注册的监听检查设施。注意:监听器的相关方式要放在测试用例之前,以保证执行用例前相应的监听事件处理已经注册,可以在执行过程中对异常情况进行处理。
与监听器相关的方法
registerWatcher() 用于注册一个监听器,如果UiSelector无法匹配到对象,将会触发监听器
removeWatcher() 用于取消之前注册的指定监听器
resetWatcherTriggers() 用于重置已触发过的UiWatcher,重置后相当于没运行过
runWatchers() 用于强制运行所有的监听器
举例:实现单击信息、手机等图标时,出现来电的异常情况下的处理方法
// 注册监听器
UiDevice.getInstance().registerWatcher(“phone”,new UiWatcher(){
public boolean checkForCondition(){ // 查询设备上所有已经注册的监听检查设施
UiSelector phone = new UiSelector().className(“android.widget.TextView”).text(“来电”);
UiObject obj = new UiObject(phone);
UiSelector reject = new UiSelector().className(“android.widget.ImageView”).description(“拒绝”);
UiObject obj1 = new UiObject(reject);
If(obj.exists()){
System.out.printIn(“出现了来电话的界面”);
}
If(obj1.exists()){
System.out.printIn(“存在挂断电话图标”);
Try{ // 挂断电话
UiDevice.getInstance().swipe(obj1.getBounds().left, obj1.getBounds().top, 573, 569, 40);
Return true;
}catch (UiObjectNotFoundException e){
e.printStackTrace();
}
}
Return false;
}
});
UiCollection u = new UiCollection(new UiSelector().className(“android.view.View”).instance(4));
UiObject obj = u.getChild(new UiSelector().className(“android.widget.TextView”).index(0));
obj.click();
UiDevice.getInstance().pressBack();
Sleep(5000);
UiCollection u1 = new UiCollection(new UiSelector().className(“android.view.View”).instance(4));
UiObject obj1 = u1.getChild(new UiSelector().className(“android.widget.TextView”).index(1));
obj1.click();
UiDevice.getInstance().pressBack();
Sleep(5000);
UiScrollable类
UiScrollable类是UiCollection的子类,用于专门处理滚动事件的对象。其继承关系为UiObject -> UiCollection ->UiScrollable。
常用API方法
setAsVerticalList() 设置Ui元素列表基于纵向滚动
setAsHorizontalList() 设置Ui元素列表基于横向滚动
getMaxSearchSwipes()
flingForward() 以步长为5快速向前移动
flingBackward() 以步长为5快速向后滑动
FlingToBeginning() 以步长为5快速滑动到滚动条起始位置
flingToEnd() UiScrollable scroll = new UiScrollable(new UiSelector().
className(“android.widget.ListView”));
scroll.flingToEnd(5); // 快速滑动到底端,步长为5
scrollForward()
scrollBackward()
scrollToEnd()
scrollToBeginning()
getChildByDescription()
getChildByInstance()
getChildByText() 打开设置的关于手机选项
// 滑动列表到最后,点击About phone选项
UiScrollable settings = new UiScrollable(new UiSelector()
.className(“android.support.v7.widget.RecyclerView”));
UiObject about = settings.getChildByText(new UiSelector()
.className(“android.widget.LinearLayout”), “About phone”);
about.click();
scrollIntoView()
scrollTextIntoView()
Configurator类
Configurator类用于设置或获取UI Automator的主要参数。使用configurator设置运行时参数,需要先调用getInstance()函数获取实例。
常用API方法
setWaitForSelectorTimeout() 设置UiSelector匹配的超时时间
getActionAcknowledgmentTimeout() 获取等待UI Automator动作响应应答的超时时间,动作包括点击、设置文本、按压菜单等常用动作。
getKeyInjectionDelay() 获取当前的文本输入时的按键间隔时间
getScrollAcknowledgmentTimeout() 获取等待UI Automator滑动动作响应应答的超时时间
getScrollAcknowledgmentTimeout() 获取等待UI Automator滑动动作响应应答的超时时间
getWaitForIdleTimeout() 获取当前的等待界面进入空闲状态的超时时间
getWaitForSelectorTimeout() 获取当前等待界面控件变为可见、被UiSelector匹配的超时时间
举例:设置等待界面控件变为可见,被UiSelector匹配的超时时间,并取出这个参数值。
Public void testConfig() throws UiObjectNotFoundException, RemoteException{
Configurator configurator = Configurator.getInstance();
Configurator.setWaitForSelectorTimeout(1000);
System.out.printIn(“WaitForSelectorTimeout:”+configurator.getWaitForSelectorTimeout());
// 获得“计算器”图标对象,并进行单击
UiObject calculator = tv.getChild(new UiSelector().className(“android.widget.TextView”).instance(3))
calculator.click();
}
UITesting框架重要类
UiTestAutomationBridge类
UiTestAutomationBridge是整个Testing Framework的基础,此类负责连接系统,记录最新的可链接事件(AccessibilityEvent) , 窗口内容查询Api等。可以被Android App调用,或者Java程序从shell调用。
重要概念及常用API方法
AccessibilityEvent 所有的Ui元素可以被操纵,因为这些Event都是AccessibilityEvent
AccessibilityNodeInfo 视窗中的组件树节点,也就是uiautomtorViewer中展示的各个节点
connect() 建立与设备的实际连接
disconnect() 断开与设备的连接
executeCommandAndWaitForAccessibilityEvent()
performAccessibilityAction()
findAccessibilityNodeInfosByText()
findAccessibilityNodeInfoByViewIdInActiveWindow()
UiAutomatorBridge类
UiAutomatorBridge是UiTestAutomationBridge的子类,增加了一些常量的定义
与UiTestAutomationBridge区别
InteractionController 构造函数中增加了InteractionController对象的调用
定义了几乎所有关于手机的基础操作
QueryController 构造函数中增加了QueryController对象的调用
executeCommandAndWaitForAccessibilityEvent()
onAccessibilityEvent()
waitForIdle()
addAccessibilityEventListener()
InteractionController类
InteractionProvider类负责注入用户事件(如点击、输入等)和反应事件的对应坐标。InteractionController则定义了几乎所有至于手机的基础操作。
常用API操作
runAndWaitForEvents()
clickAndWaitForEvents()
click()
longTap()
scrollSwipe()
Swipe()
touchUp()
touchDown()
clickAndWaitForNewWindow(),
TouchMove()
isNaturalRotation(),
setRotationRight()
setRotationLeft()
freezeRotation()
wakeDevice()
sleepDevice()
QueryController类
QueryController负责把UiSelector 的查找信息转化为AccessibilityNodeInfo。
常用API操作
findNodePatternRecursive()
translatePatternSelector()
translateReqularSelector()
translateCompoundSelector()
getRootNode()
findAccessibilityNodeInfo()