Android Android Instrumentation Test Using Espresso
Post
Cancel

Android Instrumentation Test Using Espresso

1. Introduction

1.1. What is instrumentation test?

To me, instrumentation test is simply integration test. Instrumentation test run on Android device or emulator and can access to Instrumentation information like Context, Activity,… of the app under test.

1.2. What is Espresso?

Espresso is an Android testing framework using instrumentation-based test API and and works with the AndroidJUnitRunner test runner. Espresso is used to simulate user interactions within the test app and it runs really really fast!!!

2. Set up Espresso

2.1. Added Espresso into build.gradle dependencies

Add the following lines of code into dependencies part in your app’s build.gradle file:

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

2.2. Update the instrumentation runner

Inside defaultConfig section, update the testInstrumentationRunner like below:

defaultConfig {
      testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

2.3. Disable animation on test device/emulator

To help the test run stably, you should disable all the animation on target device/emulator. Go to SettingsDeveloper Options, then disable all following animations:

  • Window animation scale
  • Transition animation scale
  • Animator duration scale

3. Espresso basics

3.1. Finding a View using View Matcher

ViewMatcher is a collection of conditions which you can use to identify a specific View in the view hierarchy.

Some common ViewMatcher:

  • withText(String text): Returns a matcher that matches TextView based on its text property value.
  • withId(int id): Returns a matcher that matches TextView based on its id property value.

You can easily locate a View in view hierarchy by using onView() with one or many ViewMatcher:

onView(withId(R.id.tv_hello))
//Find the View which has id as tv_hello

Or

onView(allOf(withId(R.id.tv_hello), withText(Goodbye))
//Find the View which has id as tv_hello AND have text as Goodbye

BIG NOTE:

You must make sure that there’s ONLY one View in the hierarchy can match your input ViewMatcher. If there’s more than one, you’ll receive an error:

Java.lang.RuntimeException:
com.google.android.apps.common.testing.ui.espresso.AmbiguousViewMatcherException:
This matcher matches multiple views in the hierarchy: (withId: is <111111111>)

3.2. Perform an action using View Action

After found the wanted View, you may want to perform some user interaction on it (like click, double click, press back, or type text,…). In order to do that, you will need the help of ViewAction.

Some common ViewAction:

  • click(): Click on a specific View
  • typeText(String text): Type a specific text into an EditText
  • scrollTo(): Scroll to a specific View to make sure it is visible before performing any other actions (like click())

Example:

onView(withId(R.id.btn_hello)).perform(scrollTo(), click());
//If the btn_hello is not visible on screen, scroll to it, then perform a click!

3.3. Assert the View / UI by View Assertion

ViewAssertions takes responsibility for asserting the View in instrumentation test. You can pass as many ViewAssertions as you want to check if the UI displays properly.

Some common ViewAssertions:

  • matches(Matcher): matches one or many conditions (Matcher)
  • doesNotExist(): check if a View is not exist in the view hierarchy

Example:

onView(withId(R.id.btn_hello)).check(matches(isDisplayed()));
//Check if the button btn_hello is displayed on the screen.

4. Example

In this part, I’ll show you a very simple sample app with some basic instrumentation test using Espresso.

The demo app contains a simple Login form with validation. We’ll write test to make sure it meets all the requirements below:

  • User should be able to login if both username and password provided.
  • User should see error message when username or password missing.

The complete test class for MainActivity:

@RunWith(AndroidJUnit4.class)
public class MainActivityTest {

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

    @Test
    public void userShouldBeAbleToLoginIfUsernameAndPasswordProvided() {
        //Type the username
        onView(withId(R.id.et_username)).perform(typeText("trinh.le"));
        //Type the password
        onView(withId(R.id.et_password)).perform(typeText("dummypassword"));
        //Click on Login button, we can use withId(R.id.btn_login) instead of withText("Login")
        onView(withText("Login")).perform(click());
        //Check if the TextView message display the proper text
        onView(allOf(withId(R.id.tv_message), withText("Login successfully!"))).check(matches(isDisplayed()));
    }

    @Test
    public void userShouldSeeErrorMessageIfUsernameMissing() {
        //Type the password
        onView(withId(R.id.et_password)).perform(typeText("dummypassowrd"));
        //Click on Login button, we can use withId(R.id.btn_login) instead of withText("Login")
        onView(withText("Login")).perform(click());
        //Check if the TextView message display the proper text
        onView(allOf(withId(R.id.tv_message), withText("You must enter both username and password!"))).check(matches(isDisplayed()));
    }

    @Test
    public void userShouldSeeErrorMessageIfPasswordMissing() {
        //Type the username
        onView(withId(R.id.et_username)).perform(typeText("trinh.le"));
        //Click on Login button, we can use withId(R.id.btn_login) instead of withText("Login")
        onView(withText("Login")).perform(click());
        //Check if the TextView message display the proper text
        onView(allOf(withId(R.id.tv_message), withText("You must enter both username and password!"))).check(matches(isDisplayed()));
    }

}

If you notice, we have this line of code:

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

So, This rule provides functional testing of a single activity. The activity under test will be launched before each test and terminated after the test complete.

The full source code of this demo can be found on Github - DemoAndroidEspresso.

5. Cheat sheets

For easier to remember, you can refer to the Espresso cheat sheet below. Goodluck!

This post is licensed under CC BY 4.0 by the author.