Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Introduction: Espresso Testing for Android

DZone's Guide to

Introduction: Espresso Testing for Android

We take a look at the Espresso framework and how to write the Java code you need to started testing your Android-based mobile apps.

· Web Dev Zone ·
Free Resource

Have you seen our HERE Twitch channel to livestream our Developer Waypoints series?

As mobile developers, we spend most of our time creating new screens or changing screens that already exist and we need to know that the code works. That is why in our development process we must use tools to verify that our application continues to work as expected and that our development meets the quality expectation of the user story. So, in this article, we will talk about Espresso Testing.

We need to ensure that:

  • we show the correct information to the user when the UI is loaded.
  • we show the desired message or screen when the user performs an action.

To meet this objective there are several types of UI tests:

  • Classic UI testing -> focuses on views and their interactions.
  • Snapshot testing -> guarantees the perfect design, leaving interactions aside.

What Is Espresso Testing? How Does it Work?

Espresso is a framework created by Google for Android that allows us to write tests on the user interface. It has a simple API, easily adapts to our needs, and eliminates the complexity of managing different threads.

Espresso Testing works basically in three blocks:

  • ViewMatchers – allows you to find an item in the view.
  • ViewActions – allows you to execute actions on the elements.
  • ViewAssertions – allows you to validate a view state.

Configuration

To make Espresso Testing work in our project, we need to add the dependencies in our ‘app/build.gradle’ file and a physical or virtual device.

dependencies {
 implementation fileTree(dir: 'libs', include: ['*.jar'])
 testImplementation 'junit:junit:4.12'

   // Android runner and rules support
 androidTestImplementation 'com.android.support.test:runner:1.0.2'
 androidTestImplementation 'com.android.support.test:rules:1.0.2'

   // Espresso
 androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

It is recommended to turn off the animations of our Android device that we will use for the tests in the developer options. An easy way to do it is by executing these commands from your terminal:

adb shell settings put global window_animation_scale 0.0 
adb shell settings put global transition_animation_scale 0.0 
adb shell settings put global animator_duration_scale 0.0

Implementation

As a small practical exercise, we have created a view with two textviews and a button where we want to evaluate that when we press the button a textview is hidden and another one is shown.

espresso android

We can create our UI test manually or automatically using Espresso's record tool.

Record Espresso

For this, we must go to the options bar of Android studio and choose Run -> Record Espresso Test.
It will launch a screen where we can go making assertions.

espresso

And at the end we will generate the test code:

@LargeTest
@RunWith(AndroidJUnit4.class)
public class RecordedTextViewToggleVisibilityTest {

  @Rule
  public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class);

  @Test
  public void textViewToggleVisibilityTest() {
    ViewInteraction textView = onView(
        allOf(withId(R.id.tv_hello), withText("Hello buddy!"),
            childAtPosition(
                childAtPosition(
                    withId(android.R.id.content),
                    0),
                0),
            isDisplayed()));
    textView.check(matches(withText("Hello buddy!")));

    ViewInteraction appCompatButton = onView(
        allOf(withId(R.id.button), withText("click me"),
            childAtPosition(
                childAtPosition(
                    withId(android.R.id.content),
                    0),
                2),
            isDisplayed()));
    appCompatButton.perform(click());

    ViewInteraction textView2 = onView(
        allOf(withId(R.id.tv_see_you), withText("See you"),
            childAtPosition(
                childAtPosition(
                    withId(android.R.id.content),
                    0),
                1),
            isDisplayed()));
    textView2.check(matches(isDisplayed()));
  }

  private static Matcher childAtPosition(
      final Matcher parentMatcher, final int position) {

    return new TypeSafeMatcher() {
      @Override
      public void describeTo(Description description) {
        description.appendText("Child at position " + position + " in parent ");
        parentMatcher.describeTo(description);
      }

      @Override
      public boolean matchesSafely(View view) {
        ViewParent parent = view.getParent();
        return parent instanceof ViewGroup && parentMatcher.matches(parent)
            && view.equals(((ViewGroup) parent).getChildAt(position));
      }
    };
  }
}

 Manual form


@LargeTest
@RunWith(AndroidJUnit4.class)
public class ManualTextViewToggleVisibilityTest {

  @Rule
  public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(MainActivity.class);

  @Test
  public void textViewToggleVisibilityTest() {


    // here we are going to look in the view tree
    // we use allOff from hamcrest library to combine matchers
    ViewInteraction tvHello = onView(allOf(withId(R.id.tv_hello),withText(R.String.hello_buddy)));

    ViewInteraction tvSeeYou = onView(allOf(withId(R.id.tv_see_you),withText(R.String.see_you)));

    // assert that textView with text 'Hello buddy!' is display
    tvHello.check(matches(isDisplayed()));


    // assert that textView with text 'See you' has visibility gone
tvSeeYou.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));

    // find button with given id and click
    onView(withId(R.id.button)).perform(click());

    // assert see you is visible and hello buddy is not.        tvHello.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
    tvSeeYou.check(matches(isDisplayed()));
  }
}

We can verify that Espresso has automatically generated more code, which can be easily broken and will require more maintenance. For example, we used the literal string to find the view, and, if we change the language to the device the test would fail. However, we can manually use the id of the string resource and add as many matchers as we need.

This Hamcrest reference guide can be useful when working with matchers.

Conclusion: Espresso Testing

As humans, we are prone to make mistakes and this implies that our software is vulnerable to bugs and defects. Espresso helps us detect errors that may have been made in the development, ensuring the reliability of the client and their satisfaction with the application.

If you have not yet added Espresso to your development tools, think about the people who will have to test the application manually.

Developer Waypoints is a live coding series from HERE, which will teach you how to build with maps and location data.

Topics:
espresso ui ,software testing ,web dev ,mobile application development

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}