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 of the desired product according to the user story. And in this article, we will talk about Espresso Testing.

Ensure that:

  • We show the correct information to the user when the UI is loaded
  • Show the desired message or screen when 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 to execute actions on the elements
  • ViewAssertions – validate a view state

Working with espresso it is advisable to have this sheet nearby.

 

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 the espresso record tool.

 

  • Record Espresso

For this we must go in the options bar of Android studio to 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 in case of changing 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 his 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.

 

If you are interested in knowing more about knowing more about Espresso Testing, I highly recommend you to subscribe to our monthly newsletter by clicking here

 

If you found this article about Espresso Testing interesting, you might like…

 

Use Kotlin for your app

iOS Objective-C app: sucessful case study

Mobile app development trends of the year

Banco Falabella wearable case study 

Mobile development projects 

Viper architecture advantages for iOS apps 

Why Kotlin ? 

Software architecture meetups

Pure MVP in Android