Automating User Interface Tests
User interface (UI) testing lets you ensure that your app meets its functional requirements and achieves a high standard of quality such that it is more likely to be successfully adopted by users.
One approach to UI testing is to simply have a human tester perform a set of user operations on the target app and verify that it is behaving correctly. However, this manual approach can be time-consuming, tedious, and error-prone. A more efficient approach is to write your UI tests such that user actions are performed in an automated way. The automated approach allows you to run your tests quickly and reliably in a repeatable manner.
Note: It is strongly encouraged that you use Android Studio for building your test apps, because it provides project setup, library inclusion, and packaging conveniences. This class assumes you are using Android Studio.
To automate UI tests with Android Studio, you implement your test code in a separate Android test folder (src/androidTest/java). The Android Plug-in for Gradle builds a test app based on your test code, then loads the test app on the same device as the target app. In your test code, you can use UI testing frameworks to simulate user interactions on the target app, in order to perform testing tasks that cover specific usage scenarios.
For testing Android apps, you typically create these types of automated UI tests:
- UI tests that span a single app: This type of test verifies that the target app behaves as expected when a user performs a specific action or enters a specific input in its activities. It allows you to check that the target app returns the correct UI output in response to user interactions in the app’s activities. UI testing frameworks like Espresso allow you to programmatically simulate user actions and test complex intra-app user interactions.
- UI tests that span multiple apps: This type of test verifies the correct behavior of interactions between different user apps or between user apps and system apps. For example, you might want to test that your camera app shares images correctly with a 3rd-party social media app, or with the default Android Photos app. UI testing frameworks that support cross-app interactions, such as UI Automator, allow you to create tests for such scenarios. The lessons in this class teach you how to use the tools and APIs in the Android Testing Support Library to build these types of automated tests. Before you begin building tests using these APIs, you must install the Android Testing Support Library, as described in Downloading the Android Testing Support Library.
UI Testing
In addition to unit testing the individual components that make up your Android application (such as activities, services, and content providers), it is also important that you test the behavior of your application’s user interface (UI) when it is running on a device. UI testing ensures that your application returns the correct UI output in response to a sequence of user actions on a device, such as entering keyboard input or pressing toolbars, menus, dialogs, images, and other UI controls.
Functional or black-box UI testing does not require testers to know the internal implementation details of the app, only its expected output when a user performs a specific action or enters a specific input. This approach allows for better separation of development and testing roles in your organization.
One common approach to UI testing is to run tests manually and verify that the app is behaving as expected. However, this approach can be time-consuming, tedious, and error-prone. A more efficient and reliable approach is to automate the UI testing with a software testing framework. Automated testing involves creating programs to perform testing tasks (test cases) to cover specific usage scenarios, and then using the testing framework to run the test cases automatically and in a repeatable manner.
Overview
he Android SDK provides the following tools to support automated, functional UI testing on your application:
uiautomatorviewer - A GUI tool to scan and analyze the UI components of an Android application.
uiautomator - A Java library containing APIs to create customized functional UI tests, and an execution engine to automate and run the tests. To use these tools, you must have the following versions of the Android development tools installed:
Android SDK Tools, Revision 21 or higher
Android SDK Platform, API 16 or higher
Workflow for the the uiautomator testing framework Here’s a short overview of the steps required to automate UI testing:
- Prepare to test by installing the app on a test device, analyzing the app’s UI components, and ensuring that your application is accessible by the test automation framework.
- Create automated tests to simulate specific user interactions on your application.
- Compile your test cases into a JAR file and install it on your test device along with your app.
- Run the tests and view the test results.
- Correct any bugs or defects discovered in testing.
Analyzing Your Application’s UI
Before you start writing your test cases, it’s helpful to familiarize yourself with the UI components (including the views and controls) of the targeted application. You can use the uiautomatorviewer tool to take a snapshot of the foreground UI screen on any Android device that is connected to your development machine. The uiautomatorviewer tool provides a convenient visual interface to inspect the layout hierarchy and view the properties of the individual UI components that are displayed on the test device. Using this information, you can later create uiautomator tests with selector objects that target specific UI components to test.
To analyze the UI components of the application that you want to test:
Connect your Android device to your development machine.
Open a terminal window and navigate to
/tools/. Run the tool with this command:
1
$ uiautomatorviewer
To capture a screen for analysis, click the Device Screenshot button in the GUI of the uiautomatorviewer tool.
Note: If you have more than one device connected, specify the device for screen capture by setting the ANDROID_SERIAL environment variable:
a. Find the serial numbers for your connected devices by running this command:
1 | $ adb devices |
#In Windows:
set ANDROID_SERIAL=
#In UNIX:
export ANDROID_SERIAL=
1 | If you are connected to only a single device, you do not need to set the ANDROID_SERIAL environment variable. |
getUiDevice().pressHome();
1 | - [UiSelector](https://stuff.mit.edu/afs/sipb/project/android/docs/tools/help/uiautomator/UiSelector.html) |
UiObject appItem = new UiObject(new UiSelector() .className(“android.widget.ListView”).instance(1) .childSelector(new UiSelector().text(“Apps”)));
1 |
|
UiObject cancelButton = new UiObject(new UiSelector().text(“Cancel”)); UiObject okButton = new UiObject(new UiSelector().text(“OK”));
1 | You can reuse the UiObject instances that you have created in other parts of your app testing, as needed. Note that the `uiautomator` test framework searches the current display for a match every time your test uses a UiObject instance to click on a UI element or query a property. |
if(okButton.exists() && okButton.isEnabled()) { okButton.click(); }
1 | You can also restrict the search to find only elements of a specific class. For example, to find matches of the Button class: |
UiObject cancelButton = new UiObject(new UiSelector().text(“Cancel”) .className(“android.widget.Button”)); UiObject okButton = new UiObject(new UiSelector().text(“OK”) .className(“android.widget.Button”));
1 | - [UiCollection](https://stuff.mit.edu/afs/sipb/project/android/docs/tools/help/uiautomator/UiCollection.html) |
UiCollection videos = new UiCollection(new UiSelector() .className(“android.widget.FrameLayout”));
1 | If the videos are listed within a LinearLayout view, and you want to to retrieve the number of videos in this collection: |
int count = videos.getChildCount(new UiSelector() .className(“android.widget.LinearLayout”));
1 | If you want to find a specific video that is labeled with the text element Cute Baby Laughing from the collection and simulate a user-click on the video: |
UiObject video = videos.getChildByText(new UiSelector() .className(“android.widget.LinearLayout”), “Cute Baby Laughing”); video.click();
1 |
|
UiObject checkBox = video.getChild(new UiSelector() .className(“android.widget.Checkbox”)); if(!checkBox.isSelected()) checkbox.click();
1 | - [UiScrollable](https://stuff.mit.edu/afs/sipb/project/android/docs/tools/help/uiautomator/UiScrollable.html) |
UiScrollable settingsItem = new UiScrollable(new UiSelector() .className(“android.widget.ListView”)); UiObject about = settingsItem.getChildByText(new UiSelector() .className(“android.widget.LinearLayout”), “About tablet”); about.click()
1 | For more information about these APIs, see the uiautomator reference. |
package com.uia.example.my;
// Import the uiautomator libraries import com.android.uiautomator.core.UiObject; import com.android.uiautomator.core.UiObjectNotFoundException; import com.android.uiautomator.core.UiScrollable; import com.android.uiautomator.core.UiSelector; import com.android.uiautomator.testrunner.UiAutomatorTestCase;
public class LaunchSettings extends UiAutomatorTestCase {
public void testDemo() throws UiObjectNotFoundException {
// Simulate a short press on the HOME button.
getUiDevice().pressHome();
// We’re now in the home screen. Next, we want to simulate
// a user bringing up the All Apps screen.
// If you use the uiautomatorviewer tool to capture a snapshot
// of the Home screen, notice that the All Apps button’s
// content-description property has the value “Apps”. We can
// use this property to create a UiSelector to find the button.
UiObject allAppsButton = new UiObject(new UiSelector()
.description("Apps"));
// Simulate a click to bring up the All Apps screen.
allAppsButton.clickAndWaitForNewWindow();
// In the All Apps screen, the Settings app is located in
// the Apps tab. To simulate the user bringing up the Apps tab,
// we create a UiSelector to find a tab with the text
// label “Apps”.
UiObject appsTab = new UiObject(new UiSelector()
.text("Apps"));
// Simulate a click to enter the Apps tab.
appsTab.click();
// Next, in the apps tabs, we can simulate a user swiping until
// they come to the Settings app icon. Since the container view
// is scrollable, we can use a UiScrollable object.
UiScrollable appViews = new UiScrollable(new UiSelector()
.scrollable(true));
// Set the swiping mode to horizontal (the default is vertical)
appViews.setAsHorizontalList();
// Create a UiSelector to find the Settings app and simulate
// a user click to launch the app.
UiObject settingsApp = appViews.getChildByText(new UiSelector()
.className(android.widget.TextView.class.getName()),
"Settings");
settingsApp.clickAndWaitForNewWindow();
// Validate that the package name is the expected one
UiObject settingsValidation = new UiObject(new UiSelector()
.packageName("com.android.settings"));
assertTrue("Unable to detect Settings",
settingsValidation.exists());
}
}
1 |
|
1 | The <name> is the name of the project that contains your uiautomator test source files, and the <path> is the path to the corresponding project directory. |
ant build
1 | 4. Deploy your generated test JAR file to the test device by using the adb push command: |
adb push
1 | Here’s an example: |
adb push ~/dev/workspace/LaunchSettings/bin/LaunchSettings.jar /data/local/tmp/
1 |
|
adb shell uiautomator runtest LaunchSettings.jar -c com.uia.example.my.LaunchSettings
1 | To learn more about the syntax, subcommands, and options for uiautomator, see the [uiautomator](https://stuff.mit.edu/afs/sipb/project/android/docs/tools/help/uiautomator/index.html) reference. |
adb shell uiautomator runtest
1 | Here’s an example: |
adb shell uiautomator runtest LaunchSettings.jar -c com.uia.example.my.LaunchSettings
#### Command-line Options
The following table describes the subcommands and options for uiautomator.
Table 1. Command-line options for uiautomator
|Subcommand| Option| Description|
|---|---|---|
|runtest| `<jar>`| Required. The <jar> argument is the name of one or more JAR files that you deployed to the target device which contain your uiautomator testcases. You can list more than one JAR file by using a space as a separator.|
||`-c <test_class_or_method>` |Required. The <test_class_or_method> argument is a list of one or more specific test classes or test methods from the JARs that you want uiautomator to run.Each class or method must be fully qualified with the package name, in one of these formats: package_name.class_name package_name.class_name#method_name You can list multiple classes or methods by using a space as a separator.|
||--nohup |Runs the test to completion on the device even if its parent process is terminated (for example, if the device is disconnected).|
||-e |<NAME> <VALUE>|Specify other name-value pairs to be passed to test classes. May be repeated.Note: The -e options cannot be combined; you must prefix each option with a separate -e flag.
||-e debug [true|false] |Wait for debugger to connect before starting.|
||dump [file] |Generate an XML file with a dump of the current UI hierarchy. If a filepath is not specified, by default, the generated dump file is stored on the device in this location `/storage/sdcard0/window_dump.xml`.|
|events|| Prints out accessibility events to the console until the connection to the device is terminated|
### [UiAutomation api](https://developer.android.com/reference/android/app/UiAutomation.html)
Class for interacting with the device's UI by simulation user actions and introspection of the screen content. It relies on the platform accessibility APIs to introspect the screen and to perform some actions on the remote view tree. It also allows injecting of arbitrary raw input events simulating user interaction with keyboards and touch devices. One can think of a UiAutomation as a special type of AccessibilityService which does not provide hooks for the service life cycle and exposes other APIs that are useful for UI test automation.
这是一个通过模拟用户操作来与设备用户界面交互以及获取屏幕内容的类。它依赖于平台的辅助功能APIs来在远程的控件树上获取屏幕内容以及执行一些操作。同时它也允许通过注入原生事件(译者注:指的就是InputEvent. KeyEvent也是继承于InputEvent的,所以说它是原生事件)来模拟用户的按键和触屏操作。我们可以认为UiAutomation就是一个特殊类型的AccessibilityService,其既不会为控制服务的生命周期而提供钩子函数,也不会暴露任何其他可以直接用于用户界面测试自动化的APIs.
The APIs exposed by this class are low-level to maximize flexibility when developing UI test automation tools and libraries. Generally, a UiAutomation client should be using a higher-level library or implement high-level functions. For example, performing a tap on the screen requires construction and injecting of a touch down and up events which have to be delivered to the system by a call to injectInputEvent(InputEvent, boolean).
这个类暴露出来的APIs是很低层的,目的就是为了在开发用户界面测试自动化框架和库时提供最大的弹性。总的来说,一个UiAutomation客户端应该使用一些(基于UiAutomation的)更高层次的库或者实现更高层次的方法。比如,模拟一个用户在屏幕上的点击事件需要构造并注入一个按下和一个弹起事件,然后必须调用UiAutomation的一个injectInputEvent(InputEvent, boolean)的调用来发送给操作系统。
The APIs exposed by this class operate across applications enabling a client to write tests that cover use cases spanning over multiple applications. For example, going to the settings application to change a setting and then interacting with another application whose behavior depends on that setting.
这个类暴露出来的APIs可以跨应用,这样用户就可以编写可以跨越多个应用的测试用例脚本了。比如,打开系统的设置应用去修改一些设置然后再与另外一个依赖于该设置的应用进行交互(译者注:这个在instrumentation这个框架可以做不到的)