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