运行Espresso和UI Automator测试时要使用模拟器。国内手机的ROM大多进行过修改,可能加入很多限制,导致测试无法正常运行。
Espresso只支持一个活动内部交互行为的测试。跨越多个活动、多个应用的场景需要使用UI Automator。使用Espresso和UI Automator的测试代码要保存在src/androidTest/目录下。在使用UI Automator时,首先要建立一个UiDevice对象。UiDevice对象表示一台设备。通过UiDevice你可以按下主页键、返回键,可以打开应用、选择界面上具有某个属性的控件等。
Listing 1: 获取UiDevice对象
val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
Listing 2: 通过UiDevice启动应用
val context = InstrumentationRegistry.getInstrumentation().targetContext val intent = context.packageManager.getLaunchIntentForPackage(packageName)?.apply { addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) } context.startActivity(intent) device.wait(Until.hasObject(By.pkg(packageName).depth(0)), timeoutMillis)
Listing 3: 通过UiDevice模拟按下主页键、返回键
device.pressHome() device.pressBack()
Listing 4: 通过UiDevice获取前台应用包名
device.currentPackageName
UiDevice提供了方法findObject(uiSelector: UiSelector):UiObject来获取界面上的某个控件。UiObject表示一个控件。UiSelector是选择控件的类。
Listing 5: 按资源id选择控件
device.findObject(UiSelector().resourceId("com.my.app:id/button_ok")
Listing 6: 按界面文字选择控件
device.findObject(UiSelector().text("click here"))
如果指定属性的控件不存在,findObject仍然会返回一个UiObject对象。此时UiObject.exists()返回false。通过UiObject可以模拟对控件的操作,比如点击click()、输入文字setText("hello, world!")等。在控件显示之前调用findObject将会得到一个exists() == false的UiObject对象。此时调用click()等方法将会引发异常。为避免此情况,可以调用UiDevice::wait或UiObject::waitForExists方法等待控件渲染完毕。
Listing 7: 使用UiDevice.wati等待控件渲染
device.wait(Until.hasObject(By.text(text)), timeoutMillis) device.wait(Until.hasObject(By.res(packageName, "${packageName}:id/${resourceId}")), timeoutMillis)
对于RecyclerView这类的列表,可以使用UiCollection来选择其中的子元素控件。UiCollection的构造函数有一个UiSelector参数,这个参数用于选择容器(如RecyclerView)控件。通过UiCollection.getChild(UiSelector)可以获取子元素控件进行操作。UiCollection只能获取已经显示出来的子元素控件。对于长的可滚动列表,如果目标子元素在屏幕之外,UiCollection或抛出异常。此时要使用UiScrollable。UiScrollable是UiCollection的派生类。从上面的介绍可以看出,UiDevice和UiObject是两个核心类,UiDevice可以对设备进行操作,UiObject可以对控件进行操作。
方法 | 说明 |
---|---|
findObject(uiSelector):UiObject | |
freezeRotation() | |
isScreenOn() | |
pressBack() | |
pressHome() | |
pressMenu() | |
pressSearch() | |
setOrientationLandscape() | |
setOrientationLeft() | |
setOrientationNatural() | |
setOrientationPortrait() | |
setOrientationRight() | |
sleep() | |
takeScreenshot(storePath, scale, quality) | |
unfreezeRotation() | |
wait(condition, timeout) | |
wait(condition, timeout) | |
waitForIdle() | |
waitForIdle(timeout) | |
wakeUp() |
方法 | 说明 |
---|---|
clearTextField() | 清除可编辑文字 |
click() | 点击 |
dragTo(uiObject,steps) | 拖拽 |
exists():Boolean | 判断存在 |
getChild(uiSelector):UiSelector | 选择子元素控件 |
getText() | 获取text属性 |
isCheckable():Boolean | |
isChecked():Boolean | |
isClickable():Boolean | |
isEnabled():Boolean | |
isFocusable():Boolean | |
isFocused():Boolean | |
isLongClickable():Boolean | |
isScrollable():Boolean | |
isSelected():Boolean | |
longClick() | |
performMultiPointerGesture(…) | |
performTwoPointerGesture(…) | |
setText(text) | |
swipeDown(steps) | |
swipeLeft(steps) | |
swipeRight(steps) | |
swipeUp(steps) | |
waitForExists(timeout) | |
waitUntilGone(timeout) |