diff options
Diffstat (limited to 'docs/html/training/testing/ui-testing/uiautomator-testing.jd')
-rw-r--r-- | docs/html/training/testing/ui-testing/uiautomator-testing.jd | 520 |
1 files changed, 520 insertions, 0 deletions
diff --git a/docs/html/training/testing/ui-testing/uiautomator-testing.jd b/docs/html/training/testing/ui-testing/uiautomator-testing.jd new file mode 100644 index 0000000..e314b70 --- /dev/null +++ b/docs/html/training/testing/ui-testing/uiautomator-testing.jd @@ -0,0 +1,520 @@ +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/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 you begin using UI Automator, you must:</p> + + <ul> + <li> + <strong>Install the Android Testing Support Library</strong>. The UI Automator API is + located under the {@code com.android.support.test.uiautomator} package. These classes allow + you to create tests that use the Espresso testing framework. To learn how to install the + library, see <a href="{@docRoot}tools/testing-support-library/index.html#setup"> + Testing Support Library Setup</a>. + </li> + + <li> + <strong>Set up your project structure.</strong> In your Gradle project, the source code for + the target app that you want to test is typically placed under the {@code app/src/main} + folder. The source code for instrumentation tests, including + your UI Automator tests, must be placed under the <code>app/src/androidTest</code> folder. + To learn more about setting up your project directory, see + <a href="{@docRoot}tools/projects/index.html">Managing Projects</a>. + </li> + + <li> + <strong>Specify your Android testing dependencies</strong>. In order for the + <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for Gradle</a> to + correctly build and run your UI Automator tests, you must specify the following libraries in + the {@code build.gradle} file of your Android app module: + + <pre> +dependencies { + androidTestCompile 'com.android.support.test:testing-support-lib:0.1' + androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.0.0' +} +</pre> + </li> + </ul> + +<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>To build a UI Automator test, create a class that extends +{@link android.test.InstrumentationTestCase}. 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 android.test.InstrumentationTestCase; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.By; + +public class CalculatorUiTest extends InstrumentationTestCase { + + private UiDevice mDevice; + + public void setUp() { + // Initialize UiDevice instance + mDevice = UiDevice.getInstance(getInstrumentation()); + + // Start from the home screen + mDevice.pressHome(); + mDevice.wait(Until.hasObject(By.pkg(getHomeScreenPackage()).depth(0)), + } +} +</pre> + +<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>UI Automator tests are based on the {@link android.app.Instrumentation} class. The +<a href="https://developer.android.com/tools/building/plugin-for-gradle.html"> + Android Plug-in for Gradle</a> +provides a default directory ({@code src/androidTest/java}) for you to store the instrumented test +classes and test suites that you want to run on a device. The plug-in compiles the test +code in that directory and then executes the test app using a test runner class. You are +strongly encouraged to use the +<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a> +class provided in the +<a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a> +as your default test runner. </p> + +<p>To run UI Automator tests in your Gradle project:</p> + +<ol> +<li>Specify +<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a> +as the default test instrumentation runner in your {@code build.gradle} file: +<pre> +android { + defaultConfig { + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } +}</pre> +</li> +<li>Run your tests from the command-line by calling the {@code connectedCheck} + (or {@code cC}) task: +<pre>./gradlew cC</pre> +</li> +</ol>
\ No newline at end of file |