diff --git a/docs/html/training/testing/ui-testing/espresso-testing.jd b/docs/html/training/testing/ui-testing/espresso-testing.jd index d3d31debc3534..3d2bca7748eec 100644 --- a/docs/html/training/testing/ui-testing/espresso-testing.jd +++ b/docs/html/training/testing/ui-testing/espresso-testing.jd @@ -24,17 +24,11 @@ trainingnavtop=true
    -
  1. - Set Up Espresso -
  2. +
  3. Set Up Espresso
  4. -
  5. - Create an Espresso Test Class -
  6. +
  7. Create an Espresso Test Class
  8. -
  9. - Run Espresso Tests on a Device or Emulator -
  10. +
  11. Run Espresso Tests on a Device or Emulator

@@ -59,31 +53,40 @@ trainingnavtop=true class="external-link">Android Testing Codelab - +

Testing user interactions within a single app helps to ensure that users do not - encounter unexpected results or have a poor experience when interacting with your app. - You should get into the habit of creating user interface (UI) tests if you need to verify + encounter unexpected results or have a poor + experience when interacting with your app. + You should get into the habit of creating + user interface (UI) tests if you need to verify that the UI of your app is functioning correctly.

The Espresso testing framework, provided by the Android Testing Support Library, - provides APIs for writing UI tests to simulate user interactions within a - single target app. Espresso tests can run on devices running Android 2.2 (API level 8) and - higher. A key benefit of using Espresso is that it provides automatic synchronization of test - actions with the UI of the app you are testing. Espresso detects when the main thread is idle, - so it is able to run your test commands at the appropriate time, improving the reliability of - your tests. This capability also relieves you from having to adding any timing workarounds, - such as a sleep period, in your test code. + provides APIs for writing UI tests to simulate + user interactions within a + single target app. Espresso tests can run on + devices running Android 2.3.3 (API level 10) and + higher. A key benefit of using Espresso is + that it provides automatic synchronization of test + actions with the UI of the app you are testing. + Espresso detects when the main thread is idle, + so it is able to run your test commands + at the appropriate time, improving the reliability of + your tests. This capability also relieves you + from having to add any timing workarounds, + such as {@link java.lang.Thread#sleep(long) Thread.sleep()} + in your test code.

- The Espresso testing framework is an instrumentation-based API and works - with the + The Espresso testing framework is + an instrumentation-based API and works with the {@code AndroidJUnitRunner} test runner.

@@ -92,105 +95,139 @@ trainingnavtop=true Set Up Espresso

-

Before building your UI test with Espresso, make sure to configure your test source code -location and project dependencies, as described in - -Getting Started with Testing.

+

+ Before building your UI test with Espresso, + make sure to configure your test source code + location and project dependencies, as described in + Getting Started with Testing. +

-

In the {@code build.gradle} file of your Android app module, you must set a dependency - reference to the Espresso library:

+

+ In the {@code build.gradle} file of your Android app + module, you must set a dependency + reference to the Espresso library: +

 dependencies {
-    ...
-    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
+    // Other dependencies ...
+    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
 }
 
-

Turn off animations on your test device — leaving system animations turned on in the test -device might cause unexpected results or may lead your test to fail. Turn off animations from -Settings by opening Developing Options and turning all the following options off: +

+ Turn off animations on your test device — + leaving system animations turned on in the test + device might cause unexpected results or may + lead your test to fail. Turn off animations from + Settings by opening Developer options + and turning all the following options off:

- -

If you want to set up your project to use Espresso features other than what the core API +

  • + Transition animation scale +
  • + +
  • + Animator duration scale +
  • + +

    + +

    + If you want to set up your project to use Espresso + features other than what the core API provides, see this resource.

    -

    - Create an Espresso Test Class -

    + -

    - To create an Espresso test, create a Java class that follows this programming model: -

    +

    + Create an Espresso Test Class +

    -
      -
    1. Find the UI component you want to test in an {@link android.app.Activity} (for example, a - sign-in button in the app) by calling the - - {@code onView()} method, or the - - {@code onData()} method for {@link android.widget.AdapterView} controls. -
    2. +

      + To create an Espresso test, create a Java + class that follows this programming model: +

      -
    3. Simulate a specific user interaction to perform on that UI component, by calling the - {@code ViewInteraction.perform()} - or - {@code DataInteraction.perform()} - method and passing in the user action (for example, click on the sign-in button). To sequence - multiple actions on the same UI component, chain them using a comma-separated list in your - method argument. -
    4. +
        +
      1. + Find the UI component you want to test in + an {@link android.app.Activity} (for example, a + sign-in button in the app) by calling the + + {@code onView()} method, or the + + {@code onData()} method for {@link android.widget.AdapterView} controls. +
      2. -
      3. Repeat the steps above as necessary, to simulate a user flow across multiple - activities in the target app. -
      4. +
      5. + Simulate a specific user interaction to + perform on that UI component, by calling the + {@code ViewInteraction.perform()} + or + {@code DataInteraction.perform()} + method and passing in the user action + (for example, click on the sign-in button). To sequence + multiple actions on the same UI component, chain them using a comma-separated list in your + method argument. +
      6. -
      7. Use the +
      8. + Repeat the steps above as necessary, to simulate a user flow across multiple + activities in the target app. +
      9. + +
      10. + Use the {@code ViewAssertions} - methods to check that the UI reflects the expected - state or behavior, after these user interactions are performed. -
      11. -
      + methods to check that the UI reflects the expected + state or behavior, after these user interactions are performed. + +
    -

    - These steps are covered in more detail in the sections below. -

    +

    + These steps are covered in more detail in the sections below. +

    -

    - The following code snippet shows how your test class might invoke this basic workflow: -

    +

    + The following code snippet shows how your test + class might invoke this basic workflow: +

     onView(withId(R.id.my_view))            // withId(R.id.my_view) is a ViewMatcher
             .perform(click())               // click() is a ViewAction
             .check(matches(isDisplayed())); // matches(isDisplayed()) is a ViewAssertion
     
    -

    Using Espresso with ActivityTestRule

    + + + +

    + Using Espresso with ActivityTestRule +

    +

    -The following section describes how to create a new Espresso test in the JUnit 4 style and use - -{@code ActivityTestRule} to reduce the amount of boilerplate code you need to write. By using - -{@code ActivityTestRule}, the testing framework launches the activity under test -before each test method annotated with @Test and before any method annotated with -@Before. The framework handles shutting down the activity after the test finishes -and all methods annotated with @After are run.

    + The following section describes how to create a + new Espresso test in the JUnit 4 style and use + {@code ActivityTestRule} + to reduce the amount of boilerplate code you need to write. By using + {@code ActivityTestRule}, + the testing framework launches the activity under test + before each test method annotated with + @Test and before any method annotated with + @Before. The framework handles + shutting down the activity after the test finishes + and all methods annotated with @After are run. +

     package com.example.android.testing.espresso.BasicSample;
    @@ -234,103 +271,57 @@ public class ChangeTextBehaviorTest {
     }
     
    -

    - Using Espresso with ActivityInstrumentationTestCase2 -

    -

    The following section describes how to migrate to Espresso if you have existing test classes -subclassed from {@link android.test.ActivityInstrumentationTestCase2} and you don't want to rewrite -them to use JUnit4.

    -

    Note: For new UI tests, we strongly recommend that you write your -test in the JUnit 4 style and use the - -{@code ActivityTestRule} class, instead of -{@link android.test.ActivityInstrumentationTestCase2}.

    -

    - If you are subclassing {@link android.test.ActivityInstrumentationTestCase2} - to create your Espresso test class, you must inject an - {@link android.app.Instrumentation} instance into your test class. This step is required in - order for your Espresso test to run with the - {@code AndroidJUnitRunner} - test runner. -

    + -

    - To do this, call the - {@link android.test.InstrumentationTestCase#injectInstrumentation(android.app.Instrumentation) injectInstrumentation()} - method and pass in the result of - - {@code InstrumentationRegistry.getInstrumentation()}, as shown in the following code - example: -

    +

    + Accessing UI Components +

    -
    -import android.support.test.InstrumentationRegistry;
    +

    + Before Espresso can interact with the app + under test, you must first specify the UI component + or view. Espresso supports the use of + Hamcrest matchers + for specifying views and adapters in your app. +

    -public class MyEspressoTest - extends ActivityInstrumentationTestCase2<MyActivity> { +

    + To find the view, call the + {@code onView()} + method and pass in a view matcher that + specifies the view that you are targeting. This is + described in more detail in + Specifying a View Matcher. + The {@code onView()} + method returns a + {@code ViewInteraction} + object that allows your test to interact with the view. + However, calling the + + {@code onView()} + method may not work if you want to locate a view in + an {@link android.support.v7.widget.RecyclerView} layout. + In this case, follow the instructions in + Locating a view in an AdapterView + instead. +

    - private MyActivity mActivity; +

    + Note: + The {@code onView()} + method does not check if the view you specified is + valid. Instead, Espresso searches only the + current view hierarchy, using the matcher provided. + If no match is found, the method throws a + {@code NoMatchingViewException}. +

    - public MyEspressoTest() { - super(MyActivity.class); - } - - @Before - public void setUp() throws Exception { - super.setUp(); - injectInstrumentation(InstrumentationRegistry.getInstrumentation()); - mActivity = getActivity(); - } - - ... -} -
    - -

    Note: Previously, {@link android.test.InstrumentationTestRunner} -would inject the {@link android.app.Instrumentation} instance, but this test runner is being -deprecated.

    - -

    - Accessing UI Components -

    - -

    - Before Espresso can interact with the app under test, you must first specify the UI component - or view. Espresso supports the use of -Hamcrest matchers - for specifying views and adapters in your app. -

    - -

    - To find the view, call the - {@code onView()} - method and pass in a view matcher that specifies the view that you are targeting. This is - described in more detail in Specifying a View Matcher. - The - {@code onView()} method returns a - - {@code ViewInteraction} - object that allows your test to interact with the view. - However, calling the - {@code onView()} method may not work if you want to locate a view in - an {@link android.widget.AdapterView} layout. In this case, follow the instructions in - Locating a view in an AdapterView instead. -

    - -

    - Note: The - {@code onView()} method does not check if the view you specified is - valid. Instead, Espresso searches only the current view hierarchy, using the matcher provided. - If no match is found, the method throws a - - {@code NoMatchingViewException}. -

    - -

    - The following code snippet shows how you might write a test that accesses an - {@link android.widget.EditText} field, enters a string of text, closes the virtual keyboard, - and then performs a button click. -

    +

    + The following code snippet shows how you might write a test that accesses an + {@link android.widget.EditText} field, + enters a string of text, closes the virtual keyboard, + and then performs a button click. +

     public void testChangeText_sameActivity() {
    @@ -344,231 +335,464 @@ public void testChangeText_sameActivity() {
     }
     
    -

    - Specifying a View Matcher -

    + +

    + Specifying a View Matcher +

    -

    - You can specify a view matcher by using these approaches: -

    +

    + You can specify a view matcher by using these approaches: +

    - -

    - To improve the performance of your Espresso tests, specify the minimum matching information - needed to find your target view. For example, if a view is uniquely identifiable by its - descriptive text, you do not need to specify that it is also assignable from the - {@link android.widget.TextView} instance. -

    + -

    - Locating a view in an AdapterView -

    +

    + Locating a view in an AdapterView +

    -

    - In an {@link android.widget.AdapterView} widget, the view is dynamically populated with child - views at runtime. If the target view you want to test is inside an - {@link android.widget.AdapterView} - (such as a {@link android.widget.ListView}, {@link android.widget.GridView}, or - {@link android.widget.Spinner}), the - - {@code onView()} method might not work because only a - subset of the views may be loaded in the current view hierarchy. -

    +

    + In an {@link android.widget.AdapterView} widget, + the view is dynamically populated with child + views at runtime. If the target view you want to test is inside an + {@link android.widget.AdapterView} + (such as a {@link android.widget.ListView}, + {@link android.widget.GridView}, or + {@link android.widget.Spinner}), the + {@code onView()} + method might not work because only a + subset of the views may be loaded in the current view hierarchy. +

    -

    - Instead, call the {@code onData()} - method to obtain a - - {@code DataInteraction} - object to access the target view element. Espresso handles loading the target view element - into the current view hierarchy. Espresso also takes care of scrolling to the target element, - and putting the element into focus. -

    - -

    - Note: The +

    + Instead, call the {@code onData()} - method does not check if if the item you specified corresponds with a view. Espresso searches - only the current view hierarchy. If no match is found, the method throws a - - {@code NoMatchingViewException}. -

    + method to obtain a + {@code DataInteraction} + object to access the target view element. + Espresso handles loading the target view element + into the current view hierarchy. Espresso + also takes care of scrolling to the target element, + and putting the element into focus. +

    -

    - The following code snippet shows how you can use the - {@code onData()} - method together - with Hamcrest matching to search for a specific row in a list that contains a given string. - In this example, the {@code LongListActivity} class contains a list of strings exposed - through a {@link android.widget.SimpleAdapter}. -

    +

    + Note: The + {@code onData()} + method does not check if the item you + specified corresponds with a view. Espresso searches + only the current view hierarchy. If no match is found, the method throws a + {@code NoMatchingViewException}. +

    + +

    + The following code snippet shows how you can use the + {@code onData()} + method together + with Hamcrest matching to search for a specific + row in a list that contains a given string. + In this example, the {@code LongListActivity} class + contains a list of strings exposed + through a {@link android.widget.SimpleAdapter}. +

     onData(allOf(is(instanceOf(Map.class)),
    -        hasEntry(equalTo(LongListActivity.ROW_TEXT), is(str))));
    +        hasEntry(equalTo(LongListActivity.ROW_TEXT), is("test input")));
     
    -

    - Performing Actions -

    + -

    - Call the {@code ViewInteraction.perform()} - or - {@code DataInteraction.perform()} - methods to - simulate user interactions on the UI component. You must pass in one or more - {@code ViewAction} - objects as arguments. Espresso fires each action in sequence according to - the given order, and executes them in the main thread. -

    +

    Performing Actions

    -

    - The - {@code ViewActions} - class provides a list of helper methods for specifying common actions. - You can use these methods as convenient shortcuts instead of creating and configuring - individual {@code ViewAction} - objects. You can specify such actions as: -

    +

    + Call the + {@code ViewInteraction.perform()} + or + {@code DataInteraction.perform()} + methods to + simulate user interactions on the UI component. You must pass in one or more + {@code ViewAction} + objects as arguments. Espresso fires each action in sequence according to + the given order, and executes them in the main thread. +

    - -

    - Verifying Results -

    +

    + If the target view is inside a {@link android.widget.ScrollView}, + perform the + {@code ViewActions.scrollTo()} + action first to display the view in the screen before other proceeding + with other actions. The + {@code ViewActions.scrollTo()} + action will have no effect if the view is already displayed. +

    -

    - Call the - {@code ViewInteraction.check()} - or - {@code DataInteraction.check()} - method to assert - that the view in the UI matches some expected state. You must pass in a - - {@code ViewAssertion} object as the argument. If the assertion fails, Espresso throws - an {@link junit.framework.AssertionFailedError}. -

    + -

    - The +

    + Test your activities in isolation with Espresso Intents +

    + +

    + Espresso Intents + enables validation and stubbing of intents sent out by an app. + With Espresso Intents, you can test an app, activity, or service in isolation + by intercepting outgoing intents, stubbing the result, and sending it back to + the component under test. +

    + +

    + To begin testing with Espresso Intents, you need + to add the following line to your app's build.gradle file: +

    + +
    +dependencies {
    +  // Other dependencies ...
    +  androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2'
    +}
    +
    + +

    + To test an intent, you need to create an instance of the + IntentsTestRule + class, which is very similar to the + ActivityTestRule + class. + The + IntentsTestRule + class initializes Espresso Intents before each test, + terminates the host activity, + and releases Espresso Intents after each test. +

    + +

    + The test class shown in the following codes snippet provides a simple + test for an explicit intent. It tests the activities and intents created in the + Building Your First App + tutorial. +

    + +
    +@Large
    +@RunWith(AndroidJUnit4.class)
    +public class SimpleIntentTest {
    +
    +    private static final String MESSAGE = "This is a test";
    +    private static final String PACKAGE_NAME = "com.example.myfirstapp";
    +
    +    /* Instantiate an IntentsTestRule object. */
    +    @Rule
    +    public IntentsTestRule≶MainActivity> mIntentsRule =
    +      new IntentsTestRule≶>(MainActivity.class);
    +
    +    @Test
    +    public void verifyMessageSentToMessageActivity() {
    +
    +        // Types a message into a EditText element.
    +        onView(withId(R.id.edit_message))
    +                .perform(typeText(MESSAGE), closeSoftKeyboard());
    +
    +        // Clicks a button to send the message to another
    +        // activity through an explicit intent.
    +        onView(withId(R.id.send_message)).perform(click());
    +
    +        // Verifies that the DisplayMessageActivity received an intent
    +        // with the correct package name and message.
    +        intended(allOf(
    +                hasComponent(hasShortClassName(".DisplayMessageActivity")),
    +                toPackage(PACKAGE_NAME),
    +                hasExtra(MainActivity.EXTRA_MESSAGE, MESSAGE)));
    +
    +    }
    +}
    +
    + +

    + For more information about Espresso Intents, see the + Espresso Intents + documentation on the Android Testing Support Library site. + You can also download the + IntentsBasicSample and + IntentsAdvancedSample + code samples. +

    + + + +

    + Testing WebViews with Espresso Web +

    + +

    + Espresso Web allows you to test {@link android.webkit.WebView} components + contained within an activity. It uses the + WebDriver API to inspect and control the + behavior of a {@link android.webkit.WebView}. +

    + +

    + To begin testing with Espresso Web, you need + to add the following line to your app's build.gradle file: +

    + +
    +dependencies {
    +  // Other dependencies ...
    +  androidTestCompile 'com.android.support.test.espresso:espresso-web:2.2.2'
    +}
    +
    + +

    + When creating a test using Espresso Web, you need to enable + JavaScript on the {@link android.webkit.WebView} when you instantiate the + ActivityTestRule + object to test the activity. In the tests, you can select + HTML elements displayed in the + {@link android.webkit.WebView} and simulate user interactions, like + entering text into a text box and then clicking a button. After the actions + are completed, you can then verify that the results on the + Web page match the results that you expect. +

    + +

    + In the following code snippet, the class tests + a {@link android.webkit.WebView} component with the id value 'webview' + in the activity being tested. + The verifyValidInputYieldsSuccesfulSubmission() test selects an + <input> element on the + Web page, enters some text, and checks text that appears in + another element. +

    + +
    +@LargeTest
    +@RunWith(AndroidJUnit4.class)
    +public class WebViewActivityTest {
    +
    +    private static final String MACCHIATO = "Macchiato";
    +    private static final String DOPPIO = "Doppio";
    +
    +    @Rule
    +    public ActivityTestRule mActivityRule =
    +        new ActivityTestRule(WebViewActivity.class,
    +            false /* Initial touch mode */, false /*  launch activity */) {
    +
    +        @Override
    +        protected void afterActivityLaunched() {
    +            // Enable JavaScript.
    +            onWebView().forceJavascriptEnabled();
    +        }
    +    }
    +
    +    @Test
    +    public void typeTextInInput_clickButton_SubmitsForm() {
    +       // Lazily launch the Activity with a custom start Intent per test
    +       mActivityRule.launchActivity(withWebFormIntent());
    +
    +       // Selects the WebView in your layout.
    +       // If you have multiple WebViews you can also use a
    +       // matcher to select a given WebView, onWebView(withId(R.id.web_view)).
    +       onWebView()
    +           // Find the input element by ID
    +           .withElement(findElement(Locator.ID, "text_input"))
    +           // Clear previous input
    +           .perform(clearElement())
    +           // Enter text into the input element
    +           .perform(DriverAtoms.webKeys(MACCHIATO))
    +           // Find the submit button
    +           .withElement(findElement(Locator.ID, "submitBtn"))
    +           // Simulate a click via JavaScript
    +           .perform(webClick())
    +           // Find the response element by ID
    +           .withElement(findElement(Locator.ID, "response"))
    +           // Verify that the response page contains the entered text
    +           .check(webMatches(getText(), containsString(MACCHIATO)));
    +    }
    +}
    +
    + +

    + For more information about Espresso Web, see the + Espresso + Web documentation on the Android Testing Support Library site.. + You can also download this code snippet as part of the + Espresso Web code sample. +

    + + + +

    + Verifying Results +

    + +

    + Call the + {@code ViewInteraction.check()} + or + {@code DataInteraction.check()} + method to assert + that the view in the UI matches some expected state. You must pass in a + {@code ViewAssertion} + object as the argument. If the assertion fails, Espresso throws + an {@link junit.framework.AssertionFailedError}. +

    + +

    + The {@code ViewAssertions} - class provides a list of helper methods for specifying common - assertions. The assertions you can use include: -

    + class provides a list of helper methods for specifying common + assertions. The assertions you can use include: +

    - + +

    + The following code snippet shows how you might + check that the text displayed in the UI has + the same value as the text previously entered in the + {@link android.widget.EditText} field. +

    -

    - The following code snippet shows how you might check that the text displayed in the UI has - the same value as the text previously entered in the - {@link android.widget.EditText} field. -

     public void testChangeText_sameActivity() {
         // Type text and then press the button.
    @@ -580,14 +804,22 @@ public void testChangeText_sameActivity() {
     }
     
    -

    Run Espresso Tests on a Device or Emulator

    + + +

    + Run Espresso Tests on a Device or Emulator +

    +

    -You can run Espresso tests from Android Studio or -from the command-line. Make sure to specify - - {@code AndroidJUnitRunner} as the default instrumentation runner in your project. + You can run Espresso tests from + Android Studio or + from the command-line. Make sure to specify + {@code AndroidJUnitRunner} + as the default instrumentation runner in your project.

    +

    -To run your Espresso test, follow the steps for running instrumented tests -described in -Getting Started with Testing.

    + To run your Espresso test, follow the steps for running instrumented tests + described in + Getting Started with Testing. +