Espresso Test Recorder – A quick How-To

Datetime:2016-08-22 23:17:22          Topic: Android Studio           Share

Introduction

On Google I/O ‘16 we’ve been informed about a bunch of new features in the newest Android Studio 2.2. Check this cool video here: What’s new in Android development tools – Google I/O 2016

Android Studio 2.2 introduces a lot of new tools which makes developer’s life a bit easier. Layout Editor and Constraint Layout, Firebase plugin integration, Jack compiler, and much more. One of the novelties is Espresso Test Recorder . This new feature lets us record user interactions on device or emulator, and then creates fully working Espresso tests code. Then you can run this tests on your device, your Continuous Integration or in Firebase Test Lab. Let’s try this!

What is Espresso Test Recorder?

Espresso is a framework for UI testing. It’s the part of the Android Testing Support Library for simulating user interactions in the application. To make the test, normally you’ll need to write code on your own. Thanks to Espresso Test Recorder, part of this job can be done automatically.

To run this new feature you need:

  • Android Studio 2.2 Preview 3

Also, you need to add Gradle dependencies for Espresso:

androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile'com.android.support.test.espresso:espresso-core:2.2.2'

Espresso in practice

To start with test recording you need to open existing project. In my case, it was an application for making notes, which has one simple screen containing two AutoCompleteTextViews, Button and RecyclerView with notes. In opened project select Run -> Record Espresso Test

Then you’ll need to select target device for running app. You can choose the physical device or emulator . Next, you’ll see “ Record Your Test ” window and the app will run on your device.

In this window, you’ll see every interaction you made on screen, every taping or text typing . We haven’t done anything, so now we see “No events recorded yet”. If I make some interaction, e.g. I’ll type some text and tap on button in the app, I’ll see new events:

These events tell me that I typed texts “Note title” and “Note message” into two TextViews and then tapped on “Add note” button.

If we want to check if we added new note correctly, we can make an assertion. You could tap on “Add Assertion” button, which creates a clickable screenshot of your current screen. You can select some element and add an assertion to it. For example, I can select some TextView and Espresso Test Recorder tool will suggest me to assert that “id/text_note_title text is Note title”

For now, there’re no many automatic assertions available. You can choose:

  • for View: exists/does not exist
  • for TextView and subclasses: text is/exists/does not exists

If you want some additional assertions, you’ll need to write it in code on your own.

After making some events, we can finish test by tapping on “Complete Recording”. In next window, we’ll be asked to choose the name for our test (there’s restriction that one UI test is created in one class). Then if we don’t have Espresso dependencies, we’ll be asked to add them:

If we have, Android Studio will generate test class for us:

package pl.droidsonroids.espressotest;
 
import android.support.test.espresso.ViewInteraction;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
 
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.replaceText;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
 
@LargeTest
@RunWith(AndroidJUnit4.class)
public class MainActivityTest {
 
  @Rule public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);
 
  @Test
  public void mainActivityTest() {
      ViewInteractionappCompatAutoCompleteTextView = onView(allOf(withId(R.id.text_note_title), isDisplayed()));
      appCompatAutoCompleteTextView.perform(click());
 
      ViewInteractionappCompatAutoCompleteTextView2 = onView(allOf(withId(R.id.text_note_title), isDisplayed()));
      appCompatAutoCompleteTextView2.perform(replaceText("Note title"));
 
      ViewInteractionappCompatAutoCompleteTextView3 = onView(allOf(withId(R.id.text_note_message), isDisplayed()));
      appCompatAutoCompleteTextView3.perform(replaceText("Note message"));
 
      ViewInteractionappCompatButton =
              onView(allOf(withId(R.id.button_add_note), withText("Add note"), isDisplayed()));
      appCompatButton.perform(click());
 
      ViewInteractiontextView = onView(allOf(withId(R.id.text_note_title),
              withText("Note title"),
              childAtPosition(childAtPosition(withId(R.id.recycler_view_notes), 0), 0),
              isDisplayed()));
      textView.check(matches(withText("Note title")));
  }
 
  private static Matcher<View> childAtPosition(final Matcher<View> parentMatcher, final int position) {
 
      return new TypeSafeMatcher<View>() {
          @Override
          public void describeTo(Descriptiondescription) {
              description.appendText("Child at position " + position + " in parent ");
              parentMatcher.describeTo(description);
          }
 
          @Override
          public boolean matchesSafely(Viewview) {
              ViewParentparent = view.getParent();
              return parent instanceof ViewGroup
                      && parentMatcher.matches(parent)
                      && view.equals(((ViewGroup) parent).getChildAt(position));
          }
      };
  }
}

As you can see, Android Studio also generated ViewMatcher for finding view at some position, in this case, used for finding the first note in our RecyclerView. It’s very time-saving.

Limitations

Because Espresso Test Recorder is still in experimental phase, it has some issues. The most important things in my opinion are:

  • limited assertions number – in most cases, we’re able to assert only that some UI element exists or doesn’t exist (the only exception is TextView with additional assertion “text is”), so we need to write other assertions in code
  • no support for IdlingResources, so if you have some animation on view or some long-running operation, you’ll need to handle it by yourself, because Espresso Test Recorder doesn’t know how long should wait and the test will fail because of unknown view
  • no support for UI interactions that are outside of your code, so Facebook, Twitter, Google+ and other external sources of UI like WebViews, Google Play dialogs, etc. need to be handled on your own

Summary

Espresso Test Recording is great for someone who hasn’t ever tried UI testing. You don’t need to know how to use Espresso for writing simple tests. You can also check how they should look like (the proper annotations, the naming convention). And in some cases, it’s quicker to record test rather than write it, mainly if we have lists with many items. However, Espresso Test Recording has many limitations, which I described previously. And it doesn’t save so much time, especially when we need to type a lot of text (which takes really a lot of time in test recording mode).

However, Espresso Test Recording has many limitations, which I described previously. And it doesn’t save so much time, especially when we need to type a lot of text (which takes really a lot of time in test recording mode).

Despite all the things, I encourage you to try this new feature and see if this is helpful for you.





About List