page.title=Testing UI for Multiple Apps page.tags=testing,ui automator trainingnavtop=true @jd:body <!-- This is the training bar --> <div id="tb-wrapper"> <div id="tb"> <h2>Dependencies and Prerequisites</h2> <ul> <li>Android 4.3 (API level 18) or higher</li> <li><a href="{@docRoot}tools/testing-support-library/index.html"> Android Testing Support Library</a></li> </ul> <h2>This lesson teaches you to</h2> <ol> <li><a href="#setup">Set Up UI Automator</a></li> <li><a href="#build">Create a UI Automator Test Class</a></li> <li><a href="#run">Run UI Automator Tests on a Device or Emulator</a></li> </ol> <h2>You should also read</h2> <ul> <li><a href="{@docRoot}reference/android/support/test/uiautomator/package-summary.html"> UI Automator API Reference</a></li> </ul> <h2>Try it out</h2> <ul> <li><a href="https://github.com/googlesamples/android-testing" class="external-link">UI Automator Code Samples</a></li> </ul> </div> </div> <p>A user interface (UI) test that involves user interactions across multiple apps lets you verify that your app behaves correctly when the user flow crosses into other apps or into the system UI. An example of such a user flow is a messaging app that lets the user enter a text message, launches the Android contact picker so that the users can select recipients to send the message to, and then returns control to the original app for the user to submit the message.</p> <p>This lesson covers how to write such UI tests using the UI Automator testing framework provided by the <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>. The UI Automator APIs let you interact with visible elements on a device, regardless of which {@link android.app.Activity} is in focus. Your test can look up a UI component by using convenient descriptors such as the text displayed in that component or its content description. UI Automator tests can run on devices running Android 4.3 (API level 18) or higher.</p> <p>The UI Automator testing framework is an instrumentation-based API and works with the <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html"> {@code AndroidJUnitRunner}</a> test runner. </p> <h2 id="setup">Set Up UI Automator</h2> <p>Before building your UI test with UI Automator, make sure to configure your test source code location and project dependencies, as described in <a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests"> Getting Started with Testing</a>.</p> <p>In the {@code build.gradle} file of your Android app module, you must set a dependency reference to the UI Automator library:</p> <pre> dependencies { ... androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1' } </pre> <p>To optimize your UI Automator testing, you should first inspect the target app’s UI components and ensure that they are accessible. These optimization tips are described in the next two sections.</p> <h3 id="inspecting-ui">Inspecting the UI on a device</h3> <p>Before designing your test, inspect the UI components that are visible on the device. To ensure that your UI Automator tests can access these components, check that these components have visible text labels, <a href="http://developer.android.com/reference/android/view/View.html#attr_android:contentDescription"> {@code android:contentDescription}</a> values, or both.</p> <p>The {@code uiautomatorviewer} tool provides a convenient visual interface to inspect the layout hierarchy and view the properties of UI components that are visible on the foreground of the device. This information lets you create more fine-grained tests using UI Automator. For example, you can create a UI selector that matches a specific visible property. </p> <p>To launch the {@code uiautomatorviewer} tool:</p> <ol> <li>Launch the target app on a physical device.</li> <li>Connect the device to your development machine.</li> <li>Open a terminal window and navigate to the {@code <android-sdk>/tools/} directory.</li> <li>Run the tool with this command: <pre>$ uiautomatorviewer</pre> </li> </ol> <p>To view the UI properties for your application:</p> <ol> <li>In the {@code uiautomatorviewer} interface, click the <strong>Device Screenshot</strong> button.</li> <li>Hover over the snapshot in the left-hand panel to see the UI components identified by the {@code uiautomatorviewertool}. The properties are listed in the lower right-hand panel and the layout hierarchy in the upper right-hand panel.</li> <li>Optionally, click on the <strong>Toggle NAF Nodes</strong> button to see UI components that are non-accessible to UI Automator. Only limited information may be available for these components.</li> </ol> <p>To learn about the common types of UI components provided by Android, see <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a>.</p> <h3>Ensuring your Activity is accessible</h3> <p>The UI Automator test framework depends on the accessibility features of the Android framework to look up individual UI elements. As a developer, you should implement these minimum optimizations in your {@link android.app.Activity} to support UI Automator:</p> <ul> <li>Use the <a href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription"> {@code android:contentDescription}</a> attribute to label the {@link android.widget.ImageButton}, {@link android.widget.ImageView}, {@link android.widget.CheckBox} and other user interface controls.</li> <li>Provide an <a href="{@docRoot}reference/android/widget/TextView.html#attr_android:hint">{@code android:hint}</a> attribute instead of a content description for {@link android.widget.EditText} fields.</li> <li>Associate an <a href="http://developer.android.com/reference/android/widget/TextView.html#attr_android:hint"> {@code android:hint}</a> attribute with any graphical icons used by controls that provide feedback to the user (for example, status or state information).</li> <li>Use the {@code uiautomatorviewer} tool to ensure that the UI component is accessible to the testing framework. You can also test the application by turning on accessibility services like TalkBack and Explore by Touch, and try using your application using only directional controls.</li> </ul> <p>Generally, app developers get accessibility support for free, courtesy of the {@link android.view.View} and {@link android.view.ViewGroup} classes. However, some apps use custom view elements to provide a richer user experience. Such custom elements won't get the accessibility support that is provided by the standard Android UI elements. If this applies to your app, make sure that it exposes the custom-drawn UI element to Android accessibility services by implementing the {@link android.view.accessibility.AccessibilityNodeProvider} class.</p> <p>If the custom view element contains a single element, make it accessible by <a href="{@docRoot}guide/topics/ui/accessibility/apps.html#accessibility-methods">implementing accessibility API methods</a>. If the custom view contains elements that are not views themselves (for example, a {@link android.webkit.WebView}, make sure it implements the {@link android.view.accessibility.AccessibilityNodeProvider} class. For container views that extend an existing container implementation (for example, a {@link android.widget.ListView}), implementing {@link android.view.accessibility.AccessibilityNodeProvider} is not necessary.</p> <p>For more information about implementing and testing accessibility, see <a href="{@docRoot}guide/topics/ui/accessibility/apps.html">Making Applications Accessible</a>.</p> <h2 id="build">Create a UI Automator Test Class</h2> <p> Your UI Automator test class should be written the same way as a JUnit 4 test class. To learn more about creating JUnit 4 test classes and using JUnit 4 assertions and annotations, see <a href="{@docRoot}training/testing/unit-testing/instrumented-unit-tests.html#build"> Create an Instrumented Unit Test Class</a>. </p> <p>Add the {@code @RunWith(AndroidJUnit4.class)} annotation at the beginning of your test class definition. You also need to specify the <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html"> {@code AndroidJUnitRunner}</a> class provided in the Android Testing Support Library as your default test runner. This step is described in more detail in <a href="#run">Run UI Automator Tests on a Device or Emulator</a>. </p> <p>Implement the following programming model in your UI Automator test class:</p> <ol> <li>Get a <a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a> object to access the device you want to test, by calling the <a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#getInstance(android.app.Instrumentation)"> {@code getInstance()}</a> method and passing it an {@link android.app.Instrumentation} object as the argument.</li> <li>Get a <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a> object to access a UI component that is displayed on the device (for example, the current view in the foreground), by calling the <a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#findObject(android.support.test.uiautomator.UiSelector)"> {@code findObject()}</a> method. </li> <li>Simulate a specific user interaction to perform on that UI component, by calling a <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a> method; for example, call <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#performMultiPointerGesture(android.view.MotionEvent.PointerCoords[]...)"> {@code performMultiPointerGesture()}</a> to simulate a multi-touch gesture, and <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#setText(java.lang.String)">{@code setText()}</a> to edit a text field. You can call on the APIs in steps 2 and 3 repeatedly as necessary to test more complex user interactions that involve multiple UI components or sequences of user actions.</li> <li>Check that the UI reflects the expected state or behavior, after these user interactions are performed. </li> </ol> <p>These steps are covered in more detail in the sections below.</p> <h3 id="accessing-ui-components">Accessing UI Components</h3> <p>The <a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a> object is the primary way you access and manipulate the state of the device. In your tests, you can call <a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a> methods to check for the state of various properties, such as current orientation or display size. Your test can use the <a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a> object to perform device-level actions, such as forcing the device into a specific rotation, pressing D-pad hardware buttons, and pressing the Home and Menu buttons.</p> <p>It’s good practice to start your test from the Home screen of the device. From the Home screen (or some other starting location you’ve chosen in the device), you can call the methods provided by the UI Automator API to select and interact with specific UI elements. </p> <p>The following code snippet shows how your test might get an instance of <a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a> and simulate a Home button press:</p> <pre> import org.junit.Before; import android.support.test.runner.AndroidJUnit4; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.By; import android.support.test.uiautomator.Until; ... @RunWith(AndroidJUnit4.class) @SdkSuppress(minSdkVersion = 18) public class ChangeTextBehaviorTest { private static final String BASIC_SAMPLE_PACKAGE = "com.example.android.testing.uiautomator.BasicSample"; private static final int LAUNCH_TIMEOUT = 5000; private static final String STRING_TO_BE_TYPED = "UiAutomator"; private UiDevice mDevice; @Before public void startMainActivityFromHomeScreen() { // Initialize UiDevice instance mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); // Start from the home screen mDevice.pressHome(); // Wait for launcher final String launcherPackage = mDevice.getLauncherPackageName(); assertThat(launcherPackage, notNullValue()); mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), LAUNCH_TIMEOUT); // Launch the app Context context = InstrumentationRegistry.getContext(); final Intent intent = context.getPackageManager() .getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE); // Clear out any previous instances intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); context.startActivity(intent); // Wait for the app to appear mDevice.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)), LAUNCH_TIMEOUT); } } </pre> <p>In the example, the {@code @SdkSuppress(minSdkVersion = 18)} statement helps to ensure that tests will only run on devices with Android 4.3 (API level 18) or higher, as required by the UI Automator framework.</p> <p>Use the <a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#findObject(android.support.test.uiautomator.UiSelector)">{@code findObject()}</a> method to retrieve a <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a> which represents a view that matches a given selector criteria. You can reuse the <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a> instances that you have created in other parts of your app testing, as needed. Note that the UI Automator test framework searches the current display for a match every time your test uses a <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a> instance to click on a UI element or query a property.</p> <p>The following snippet shows how your test might construct <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a> instances that represent a Cancel button and a OK button in an app.</p> <pre> UiObject cancelButton = mDevice.findObject(new UiSelector() .text("Cancel")) .className("android.widget.Button")); UiObject okButton = mDevice.findObject(new UiSelector() .text("OK")) .className("android.widget.Button")); // Simulate a user-click on the OK button, if found. if(okButton.exists() && okButton.isEnabled()) { okButton.click(); } </pre> <h4 id="specifying-selector">Specifying a selector</h4> <p>If you want to access a specific UI component in an app, use the <a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a> class. This class represents a query for specific elements in the currently displayed UI. </p> <p>If more than one matching element is found, the first matching element in the layout hierarchy is returned as the target <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>. When constructing a <a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>, you can chain together multiple properties to refine your search. If no matching UI element is found, a <a href="{@docRoot}reference/android/support/test/uiautomator/UiObjectNotFoundException.html"> {@code UiAutomatorObjectNotFoundException}</a> is thrown. </p> <p>You can use the <a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html#childSelector(android.support.test.uiautomator.UiSelector)"> {@code childSelector()}</a> method to nest multiple <a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a> instances. For example, the following code example shows how your test might specify a search to find the first {@link android.widget.ListView} in the currently displayed UI, then search within that {@link android.widget.ListView} to find a UI element with the text property Apps.</p> <pre> UiObject appItem = new UiObject(new UiSelector() .className("android.widget.ListView") .instance(1) .childSelector(new UiSelector() .text("Apps"))); </pre> <p>As a best practice, when specifying a selector, you should use a Resource ID (if one is assigned to a UI element) instead of a text element or content-descriptor. Not all elements have a text element (for example, icons in a toolbar). Text selectors are brittle and can lead to test failures if there are minor changes to the UI. They may also not scale across different languages; your text selectors may not match translated strings.</p> <p>It can be useful to specify the object state in your selector criteria. For example, if you want to select a list of all checked elements so that you can uncheck them, call the <a href="{@docRoot}reference/android/support/test/uiautomator/By.html#checked(boolean)"> {@code checked()}</a> method with the argument set to {@code true}.</p> <h3 id="performing-actions">Performing Actions</h3> <p>Once your test has obtained a <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a> object, you can call the methods in the <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a> class to perform user interactions on the UI component represented by that object. You can specify such actions as:</p> <ul> <li> <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#click()"> {@code click()}</a> : Clicks the center of the visible bounds of the UI element.</li> <li> <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#dragTo(int, int, int)"> {@code dragTo()}</a> : Drags this object to arbitrary coordinates.</li> <li> <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#setText(java.lang.String)"> {@code setText()}</a> : Sets the text in an editable field, after clearing the field's content. Conversely, the <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#clearTextField()"> {@code clearTextField()}</a> method clears the existing text in an editable field.</li> <li> <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeUp(int)"> {@code swipeUp()}</a> : Performs the swipe up action on the <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>. Similarly, the <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeDown(int)"> {@code swipeDown()}</a>, <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeLeft(int)"> {@code swipeLeft()}</a>, and <a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeRight(int)"> {@code swipeRight()}</a> methods perform corresponding actions.</li> </ul> <p>The UI Automator testing framework allows you to send an {@link android.content.Intent} or launch an {@link android.app.Activity} without using shell commands, by getting a {@link android.content.Context} object through {@link android.app.Instrumentation#getContext() getContext()}.</p> <p>The following snippet shows how your test can use an {@link android.content.Intent} to launch the app under test. This approach is useful when you are only interested in testing the calculator app, and don't care about the launcher.</p> <pre> public void setUp() { ... // Launch a simple calculator app Context context = getInstrumentation().getContext(); Intent intent = context.getPackageManager() .getLaunchIntentForPackage(CALC_PACKAGE); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); // Clear out any previous instances context.startActivity(intent); mDevice.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT); } </pre> <h4 id="actions-on-collections">Performing actions on collections</h4> <p>Use the <a href="{@docRoot}reference/android/support/test/uiautomator/UiCollection.html"> {@code UiCollection}</a> class if you want to simulate user interactions on a collection of items (for example, songs in a music album or a list of emails in an Inbox). To create a <a href="{@docRoot}reference/android/support/test/uiautomator/UiCollection.html"> {@code UiCollection}</a> object, specify a <a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a> that searches for a UI container or a wrapper of other child UI elements, such as a layout view that contains child UI elements.</p> <p>The following code snippet shows how your test might construct a <a href="{@docRoot}reference/android/support/test/uiautomator/UiCollection.html"> {@code UiCollection}</a> to represent a video album that is displayed within a {@link android.widget.FrameLayout}:</p> <pre> UiCollection videos = new UiCollection(new UiSelector() .className("android.widget.FrameLayout")); // Retrieve the number of videos in this collection: int count = videos.getChildCount(new UiSelector() .className("android.widget.LinearLayout")); // Find a specific video and simulate a user-click on it UiObject video = videos.getChildByText(new UiSelector() .className("android.widget.LinearLayout"), "Cute Baby Laughing"); video.click(); // Simulate selecting a checkbox that is associated with the video UiObject checkBox = video.getChild(new UiSelector() .className("android.widget.Checkbox")); if(!checkBox.isSelected()) checkbox.click(); </pre> <h4 id="actions-on-scrollable-views">Performing actions on scrollable views</h4> <p>Use the <a href="{@docRoot}reference/android/support/test/uiautomator/UiScrollable.html"> {@code UiScrollable}</a> class to simulate vertical or horizontal scrolling across a display. This technique is helpful when a UI element is positioned off-screen and you need to scroll to bring it into view.</p> <p>The following code snippet shows how to simulate scrolling down the Settings menu and clicking on an About tablet option:</p> <pre> UiScrollable settingsItem = new UiScrollable(new UiSelector() .className("android.widget.ListView")); UiObject about = settingsItem.getChildByText(new UiSelector() .className("android.widget.LinearLayout"), "About tablet"); about.click(); </pre> <h3 id="verifying-results">Verifying Results</h3> <p>The {@link android.test.InstrumentationTestCase} extends {@link junit.framework.TestCase}, so you can use standard JUnit <a href="http://junit.org/javadoc/latest/org/junit/Assert.html" class="external-link">{@code Assert}</a> methods to test that UI components in the app return the expected results. </p> <p>The following snippet shows how your test can locate several buttons in a calculator app, click on them in order, then verify that the correct result is displayed.</p> <pre> private static final String CALC_PACKAGE = "com.myexample.calc"; public void testTwoPlusThreeEqualsFive() { // Enter an equation: 2 + 3 = ? mDevice.findObject(new UiSelector() .packageName(CALC_PACKAGE).resourceId("two")).click(); mDevice.findObject(new UiSelector() .packageName(CALC_PACKAGE).resourceId("plus")).click(); mDevice.findObject(new UiSelector() .packageName(CALC_PACKAGE).resourceId("three")).click(); mDevice.findObject(new UiSelector() .packageName(CALC_PACKAGE).resourceId("equals")).click(); // Verify the result = 5 UiObject result = mDevice.findObject(By.res(CALC_PACKAGE, "result")); assertEquals("5", result.getText()); } </pre> <h2 id="run">Run UI Automator Tests on a Device or Emulator</h2> <p> You can run UI Automator tests from <a href="{@docRoot}studio/index.html">Android Studio</a> or from the command-line. Make sure to specify <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html"> {@code AndroidJUnitRunner}</a> as the default instrumentation runner in your project. </p> <p> To run your UI Automator test, follow the steps for running instrumented tests described in <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests"> Getting Started with Testing</a>. </p>