• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Testing UI for Multiple Apps
2page.tags=testing,ui automator
3trainingnavtop=true
4
5@jd:body
6
7<!-- This is the training bar -->
8<div id="tb-wrapper">
9<div id="tb">
10  <h2>Dependencies and Prerequisites</h2>
11
12  <ul>
13    <li>Android 4.3 (API level 18) or higher</li>
14    <li><a href="{@docRoot}tools/testing-support-library/index.html">
15      Android Testing Support Library</a></li>
16  </ul>
17
18  <h2>This lesson teaches you to</h2>
19
20  <ol>
21    <li><a href="#setup">Set Up UI Automator</a></li>
22    <li><a href="#build">Create a UI Automator Test Class</a></li>
23    <li><a href="#run">Run UI Automator Tests on a Device or Emulator</a></li>
24  </ol>
25
26  <h2>You should also read</h2>
27
28  <ul>
29    <li><a href="{@docRoot}reference/android/support/test/uiautomator/package-summary.html">
30UI Automator API Reference</a></li>
31  </ul>
32
33  <h2>Try it out</h2>
34
35  <ul>
36    <li><a href="https://github.com/googlesamples/android-testing"
37class="external-link">UI Automator Code Samples</a></li>
38  </ul>
39</div>
40</div>
41
42<p>A user interface (UI) test that involves user interactions across multiple apps lets you
43verify that your app behaves correctly when the user flow crosses into other apps or into the
44system UI. An example of such a user flow is a messaging app that lets the user enter a text
45message, launches the Android contact picker so that the users can select recipients to send the
46message to, and then returns control to the original app for the user to submit the message.</p>
47
48<p>This lesson covers how to write such UI tests using the
49UI Automator testing framework provided by the
50<a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
51The UI Automator APIs let you interact with visible elements on a device, regardless of
52which {@link android.app.Activity} is in focus. Your test can look up a UI component by using
53convenient descriptors such as the text displayed in that component or its content description. UI
54Automator tests can run on devices running Android 4.3 (API level 18) or higher.</p>
55
56<p>The UI Automator testing framework is an instrumentation-based API and works
57with the
58<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
59  {@code AndroidJUnitRunner}</a>
60test runner.
61</p>
62
63<h2 id="setup">Set Up UI Automator</h2>
64
65<p>Before building your UI test with UI Automator, make sure to configure your test source code
66location and project dependencies, as described in
67<a href="{@docRoot}training/testing/start/index.html#config-instrumented-tests">
68Getting Started with Testing</a>.</p>
69
70<p>In the {@code build.gradle} file of your Android app module, you must set a dependency
71  reference to the UI Automator library:</p>
72
73<pre>
74dependencies {
75    ...
76    androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
77}
78</pre>
79
80<p>To optimize your UI Automator testing, you should first inspect the target app’s UI components
81and ensure that they are accessible. These optimization tips are described in the next two
82sections.</p>
83
84<h3 id="inspecting-ui">Inspecting the UI on a device</h3>
85<p>Before designing your test, inspect the UI components that are visible on the device. To
86ensure that your UI Automator tests can access these components, check that these components
87have visible text labels,
88<a href="http://developer.android.com/reference/android/view/View.html#attr_android:contentDescription">
89{@code android:contentDescription}</a>
90values, or both.</p>
91
92<p>The {@code uiautomatorviewer} tool provides a convenient visual interface to inspect the layout
93hierarchy and view the properties of UI components that are visible on the foreground of the device.
94This information lets you create more fine-grained tests using UI Automator. For example, you can
95create a UI selector that matches a specific visible property. </p>
96
97<p>To launch the {@code uiautomatorviewer} tool:</p>
98
99<ol>
100  <li>Launch the target app on a physical device.</li>
101  <li>Connect the device to your development machine.</li>
102  <li>Open a terminal window and navigate to the {@code <android-sdk>/tools/} directory.</li>
103  <li>Run the tool with this command:
104<pre>$ uiautomatorviewer</pre>
105  </li>
106</ol>
107
108<p>To view the UI properties for your application:</p>
109
110<ol>
111  <li>In the {@code uiautomatorviewer} interface, click the <strong>Device Screenshot</strong>
112button.</li>
113  <li>Hover over the snapshot in the left-hand panel to see the UI components identified by the
114{@code uiautomatorviewertool}. The properties are listed in the lower right-hand panel and the
115layout hierarchy in the upper right-hand panel.</li>
116  <li>Optionally, click on the <strong>Toggle NAF Nodes</strong> button to see UI components that
117are non-accessible to UI Automator. Only limited information may be available for these
118components.</li>
119</ol>
120
121<p>To learn about the common types of UI components provided by Android, see
122<a href="{@docRoot}guide/topics/ui/index.html">User Interface</a>.</p>
123
124<h3>Ensuring your Activity is accessible</h3>
125<p>The UI Automator test framework depends on the accessibility features of the Android framework
126to look up individual UI elements. As a developer, you should implement these minimum
127optimizations in your {@link android.app.Activity} to support UI Automator:</p>
128
129<ul>
130<li>Use the
131<a href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription">
132  {@code android:contentDescription}</a>
133attribute to label the {@link android.widget.ImageButton}, {@link android.widget.ImageView},
134{@link android.widget.CheckBox} and other user interface controls.</li>
135<li>Provide an <a href="{@docRoot}reference/android/widget/TextView.html#attr_android:hint">{@code android:hint}</a>
136attribute instead of a content description for {@link android.widget.EditText} fields.</li>
137<li>Associate an <a href="http://developer.android.com/reference/android/widget/TextView.html#attr_android:hint">
138  {@code android:hint}</a>
139attribute with any graphical icons used by controls that provide feedback to the user
140(for example, status or state information).</li>
141<li>Use the {@code uiautomatorviewer} tool to ensure that the UI component is accessible to the
142testing framework. You can also test the application by turning on accessibility services like
143TalkBack and Explore by Touch, and try using your application using only directional controls.</li>
144</ul>
145
146<p>Generally, app developers get accessibility support for free, courtesy of
147the {@link android.view.View} and {@link android.view.ViewGroup}
148classes. However, some apps use custom view elements to provide a richer user experience. Such
149custom elements won't get the accessibility support that is provided by the standard Android UI
150elements. If this applies to your app, make sure that it exposes the custom-drawn UI element to
151Android accessibility services by implementing the
152{@link android.view.accessibility.AccessibilityNodeProvider} class.</p>
153
154<p>If the custom view element contains a single element, make it accessible by
155<a href="{@docRoot}guide/topics/ui/accessibility/apps.html#accessibility-methods">implementing
156accessibility API methods</a>.
157If the custom view contains elements that are not views themselves (for example, a
158{@link android.webkit.WebView}, make sure it implements the
159{@link android.view.accessibility.AccessibilityNodeProvider} class. For container views that
160extend an existing container implementation
161(for example, a {@link android.widget.ListView}), implementing
162{@link android.view.accessibility.AccessibilityNodeProvider} is not necessary.</p>
163
164<p>For more information about implementing and testing accessibility, see
165<a href="{@docRoot}guide/topics/ui/accessibility/apps.html">Making Applications Accessible</a>.</p>
166
167<h2 id="build">Create a UI Automator Test Class</h2>
168
169<p>
170Your UI Automator test class should be written the same way as a JUnit 4 test class. To learn more
171about creating JUnit 4 test classes and using JUnit 4 assertions and annotations, see
172<a href="{@docRoot}training/testing/unit-testing/instrumented-unit-tests.html#build">
173Create an Instrumented Unit Test Class</a>.
174</p>
175<p>Add the {@code @RunWith(AndroidJUnit4.class)} annotation at the beginning of your test class
176definition. You also need to specify the
177<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
178{@code AndroidJUnitRunner}</a> class
179provided in the Android Testing Support Library as your default test runner. This step is described
180in more detail in <a href="#run">Run UI Automator Tests on a Device or Emulator</a>.
181</p>
182
183<p>Implement the following programming model in your UI Automator test class:</p>
184
185<ol>
186<li>Get a
187  <a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
188  object to access the device you want to test, by calling the
189<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#getInstance(android.app.Instrumentation)">
190{@code getInstance()}</a>
191method and passing it an {@link android.app.Instrumentation} object as the argument.</li>
192<li>Get a
193<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
194object to access a UI component that is displayed on the device
195	(for example, the current view in the foreground), by calling the
196<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#findObject(android.support.test.uiautomator.UiSelector)">
197  {@code findObject()}</a>
198method.
199</li>
200<li>Simulate a specific user interaction to perform on that UI component, by calling a
201<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
202method; for example, call
203<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#performMultiPointerGesture(android.view.MotionEvent.PointerCoords[]...)">
204  {@code performMultiPointerGesture()}</a>
205to simulate a multi-touch gesture, and
206<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#setText(java.lang.String)">{@code setText()}</a>
207to edit a text field. You can call on the APIs in steps 2 and 3 repeatedly as necessary to test
208more complex user interactions that involve multiple UI components or sequences of user actions.</li>
209<li>Check that the UI reflects the expected state or behavior, after these user interactions are
210	performed. </li>
211</ol>
212
213<p>These steps are covered in more detail in the sections below.</p>
214
215<h3 id="accessing-ui-components">Accessing UI Components</h3>
216<p>The
217<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
218  object is the primary way you access and manipulate the state of the
219device. In your tests, you can call
220<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
221methods to check for the state of various properties, such as current orientation or display size.
222Your test can use the
223<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
224object to perform device-level actions, such as forcing the device into a specific rotation,
225pressing D-pad hardware buttons, and pressing the Home and Menu buttons.</p>
226
227<p>It’s good practice to start your test from the Home screen of the device. From the Home screen
228(or some other starting location you’ve chosen in the device), you can call the methods provided by
229the UI Automator API to select and interact with specific UI elements. </p>
230
231<p>The following code snippet shows how your test might get an instance of
232<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
233and simulate a Home button press:</p>
234
235<pre>
236import org.junit.Before;
237import android.support.test.runner.AndroidJUnit4;
238import android.support.test.uiautomator.UiDevice;
239import android.support.test.uiautomator.By;
240import android.support.test.uiautomator.Until;
241...
242
243&#64;RunWith(AndroidJUnit4.class)
244&#64;SdkSuppress(minSdkVersion = 18)
245public class ChangeTextBehaviorTest {
246
247    private static final String BASIC_SAMPLE_PACKAGE
248            = "com.example.android.testing.uiautomator.BasicSample";
249    private static final int LAUNCH_TIMEOUT = 5000;
250    private static final String STRING_TO_BE_TYPED = "UiAutomator";
251    private UiDevice mDevice;
252
253    &#64;Before
254    public void startMainActivityFromHomeScreen() {
255        // Initialize UiDevice instance
256        mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
257
258        // Start from the home screen
259        mDevice.pressHome();
260
261        // Wait for launcher
262        final String launcherPackage = mDevice.getLauncherPackageName();
263        assertThat(launcherPackage, notNullValue());
264        mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)),
265                LAUNCH_TIMEOUT);
266
267        // Launch the app
268        Context context = InstrumentationRegistry.getContext();
269        final Intent intent = context.getPackageManager()
270                .getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE);
271        // Clear out any previous instances
272        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
273        context.startActivity(intent);
274
275        // Wait for the app to appear
276        mDevice.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
277                LAUNCH_TIMEOUT);
278    }
279}
280</pre>
281
282<p>In the example, the {@code @SdkSuppress(minSdkVersion = 18)} statement helps to ensure that
283  tests will only run on devices with Android 4.3 (API level 18) or higher, as required by the
284  UI Automator framework.</p>
285
286<p>Use the
287<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#findObject(android.support.test.uiautomator.UiSelector)">{@code findObject()}</a>
288method to retrieve a
289<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
290which represents a view that matches a given selector criteria. You can reuse the
291<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
292instances that you have created in other parts of your app testing, as needed. Note that the
293UI Automator test framework searches the current display for a match every time your test uses a
294<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
295instance to click on a UI element or query a property.</p>
296
297<p>The following snippet shows how your test might construct
298<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
299instances that represent a Cancel button and a OK button in an app.</p>
300
301<pre>
302UiObject cancelButton = mDevice.findObject(new UiSelector()
303        .text("Cancel"))
304        .className("android.widget.Button"));
305UiObject okButton = mDevice.findObject(new UiSelector()
306        .text("OK"))
307        .className("android.widget.Button"));
308
309// Simulate a user-click on the OK button, if found.
310if(okButton.exists() &#38;&#38; okButton.isEnabled()) {
311    okButton.click();
312}
313</pre>
314
315<h4 id="specifying-selector">Specifying a selector</h4>
316<p>If you want to access a specific UI component in an app, use the
317<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>
318class. This class represents a query for specific elements in the currently displayed UI. </p>
319
320<p>If more than one matching element is found, the first matching element in the layout hierarchy
321is returned as the target
322<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>.
323When constructing a
324<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>,
325you can chain together multiple properties to refine your search. If no matching UI element is
326found, a
327<a href="{@docRoot}reference/android/support/test/uiautomator/UiObjectNotFoundException.html">
328{@code UiAutomatorObjectNotFoundException}</a> is thrown. </p>
329
330<p>You can use the
331<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html#childSelector(android.support.test.uiautomator.UiSelector)">
332{@code childSelector()}</a> method to nest multiple
333<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>
334instances. For example, the following code example shows how your test might specify a search to
335find the first {@link android.widget.ListView} in the currently displayed UI, then search within that
336{@link android.widget.ListView} to find a UI element with the text property Apps.</p>
337
338<pre>
339UiObject appItem = new UiObject(new UiSelector()
340        .className("android.widget.ListView")
341        .instance(1)
342        .childSelector(new UiSelector()
343        .text("Apps")));
344</pre>
345
346<p>As a best practice, when specifying a selector, you should use a Resource ID (if one is assigned
347to a UI element) instead of a text element or content-descriptor. Not all elements have a text
348element (for example, icons in a toolbar). Text selectors are brittle and can lead to test failures
349if there are minor changes to the UI. They may also not scale across different languages; your text
350selectors may not match translated strings.</p>
351
352<p>It can be useful to specify the object state in your selector criteria. For example, if you want
353to select a list of all checked elements so that you can uncheck them, call the
354<a href="{@docRoot}reference/android/support/test/uiautomator/By.html#checked(boolean)">
355{@code checked()}</a>
356method with the argument set to {@code true}.</p>
357
358<h3 id="performing-actions">Performing Actions</h3>
359
360<p>Once your test has obtained a
361<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
362object, you can call the methods in the
363<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
364class to perform user interactions on the UI component represented by that
365object. You can specify such actions as:</p>
366
367<ul>
368<li>
369<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#click()">
370  {@code click()}</a>
371: Clicks the center of the visible bounds of the UI element.</li>
372<li>
373<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#dragTo(int, int, int)">
374  {@code dragTo()}</a>
375: Drags this object to arbitrary coordinates.</li>
376<li>
377<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#setText(java.lang.String)">
378  {@code setText()}</a>
379: Sets the text in an editable field, after clearing the field's content.
380Conversely, the
381<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#clearTextField()">
382  {@code clearTextField()}</a>
383method clears the existing text in an editable field.</li>
384<li>
385<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeUp(int)">
386  {@code swipeUp()}</a>
387: Performs the swipe up action on the
388<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>.
389Similarly, the
390<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeDown(int)">
391  {@code swipeDown()}</a>,
392<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeLeft(int)">
393  {@code swipeLeft()}</a>, and
394<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeRight(int)">
395  {@code swipeRight()}</a>
396methods perform corresponding actions.</li>
397</ul>
398
399<p>The UI Automator testing framework allows you to send an
400{@link android.content.Intent}
401or launch an {@link android.app.Activity}
402without using shell commands, by getting a
403{@link android.content.Context}
404object through
405{@link android.app.Instrumentation#getContext() getContext()}.</p>
406
407<p>The following snippet shows how your test can use an
408{@link android.content.Intent} to launch the app under test. This approach is useful when you are
409only interested in testing the calculator app, and don't care about the launcher.</p>
410
411<pre>
412public void setUp() {
413    ...
414
415    // Launch a simple calculator app
416    Context context = getInstrumentation().getContext();
417    Intent intent = context.getPackageManager()
418            .getLaunchIntentForPackage(CALC_PACKAGE);
419    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
420            // Clear out any previous instances
421    context.startActivity(intent);
422    mDevice.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT);
423}
424</pre>
425
426<h4 id="actions-on-collections">Performing actions on collections</h4>
427
428<p>Use the
429<a href="{@docRoot}reference/android/support/test/uiautomator/UiCollection.html">
430  {@code UiCollection}</a>
431class if you want to simulate user interactions on a
432collection of items (for example, songs in a music album or a list of emails in an Inbox). To
433create a
434<a href="{@docRoot}reference/android/support/test/uiautomator/UiCollection.html">
435  {@code UiCollection}</a>
436object, specify a
437<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>
438that searches for a
439UI container or a wrapper of other child UI elements, such as a layout view that contains child UI
440elements.</p>
441
442<p>The following code snippet shows how your test might construct a
443<a href="{@docRoot}reference/android/support/test/uiautomator/UiCollection.html">
444  {@code UiCollection}</a>
445to represent a video album that is displayed within a {@link android.widget.FrameLayout}:</p>
446
447<pre>
448UiCollection videos = new UiCollection(new UiSelector()
449        .className("android.widget.FrameLayout"));
450
451// Retrieve the number of videos in this collection:
452int count = videos.getChildCount(new UiSelector()
453        .className("android.widget.LinearLayout"));
454
455// Find a specific video and simulate a user-click on it
456UiObject video = videos.getChildByText(new UiSelector()
457        .className("android.widget.LinearLayout"), "Cute Baby Laughing");
458video.click();
459
460// Simulate selecting a checkbox that is associated with the video
461UiObject checkBox = video.getChild(new UiSelector()
462        .className("android.widget.Checkbox"));
463if(!checkBox.isSelected()) checkbox.click();
464</pre>
465
466<h4 id="actions-on-scrollable-views">Performing actions on scrollable views</h4>
467<p>Use the
468<a href="{@docRoot}reference/android/support/test/uiautomator/UiScrollable.html">
469  {@code UiScrollable}</a>
470class to simulate vertical or horizontal scrolling across a display. This technique is helpful when
471a UI element is positioned off-screen and you need to scroll to bring it into view.</p>
472
473<p>The following code snippet shows how to simulate scrolling down the Settings menu and clicking
474on an About tablet option:</p>
475
476<pre>
477UiScrollable settingsItem = new UiScrollable(new UiSelector()
478        .className("android.widget.ListView"));
479UiObject about = settingsItem.getChildByText(new UiSelector()
480        .className("android.widget.LinearLayout"), "About tablet");
481about.click();
482</pre>
483
484<h3 id="verifying-results">Verifying Results</h3>
485<p>The {@link android.test.InstrumentationTestCase} extends {@link junit.framework.TestCase}, so
486you can use standard JUnit <a href="http://junit.org/javadoc/latest/org/junit/Assert.html"
487class="external-link">{@code Assert}</a> methods to test
488that UI components in the app return the expected results. </p>
489
490<p>The following snippet shows how your test can locate several buttons in a calculator app, click
491on them in order, then verify that the correct result is displayed.</p>
492
493<pre>
494private static final String CALC_PACKAGE = "com.myexample.calc";
495
496public void testTwoPlusThreeEqualsFive() {
497    // Enter an equation: 2 + 3 = ?
498    mDevice.findObject(new UiSelector()
499            .packageName(CALC_PACKAGE).resourceId("two")).click();
500    mDevice.findObject(new UiSelector()
501            .packageName(CALC_PACKAGE).resourceId("plus")).click();
502    mDevice.findObject(new UiSelector()
503            .packageName(CALC_PACKAGE).resourceId("three")).click();
504    mDevice.findObject(new UiSelector()
505            .packageName(CALC_PACKAGE).resourceId("equals")).click();
506
507    // Verify the result = 5
508    UiObject result = mDevice.findObject(By.res(CALC_PACKAGE, "result"));
509    assertEquals("5", result.getText());
510}
511</pre>
512
513<h2 id="run">Run UI Automator Tests on a Device or Emulator</h2>
514<p>
515You can run UI Automator tests from <a href="{@docRoot}studio/index.html">Android Studio</a> or
516from the command-line. Make sure to specify
517<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
518  {@code AndroidJUnitRunner}</a> as the default instrumentation runner in your project.
519</p>
520<p>
521To run your UI Automator test, follow the steps for running instrumented tests
522described in <a href="{@docRoot}training/testing/start/index.html#run-instrumented-tests">
523Getting Started with Testing</a>.
524</p>