Espresso Framework

Espresso — Mobile Automation Framework for Android — Part 2

App Devops
6 min readOct 10, 2022

--

Anatomy of an Espresso Test

Shown below, is a simplified Espresso test flow.

  1. Launch the test execution using AndroidJUnit4 runner class
  2. Launch the app UI using ActivityTestRule class
  3. Locate the UI element on which an user input action or a validation needs to be done using Espresso, ViewInteraction and ViewMatchers classes
  4. Simulate a user input action on the located UI element using ViewInteraction and ViewActions class
  5. Validate the state of the located UI interaction using ViewInteraction and ViewAssertions class

Going forward we will be using this terminology in the rest of the course.

The AndroidJUnitRunner4 class:

  • Is an implementation of JUnit runner class
  • Is provided by AndroidX testing framework under the library androidx.test.ext.junit.runners
  • Enables JUnit to load, execute and report the results of Espresso test cases written in JUnit3 and JUnit4 style on Android devices or emulators

To launch the Espresso test execution using AndroidJUnitRunner4, we need to annotate the test class using @RunWith annotation (provided by JUnit) and then pass AndroidJUnitRunner4.class as argument for the @RunWith annotation, as specified below:

@RunWith(AndroidJUnit4.class)
class SampleTest {
//test case
}

The ActivityTestRule class:

  • Is an implementation of Android Activity class
  • Is provided by AndroidX testing framework under the library androidx.test.rule
  • Provides the functionality of launching a single activity of app under test and assigning it to a new object reference, before the execution any methods annotated with @Test and @before annotations.
  • Also provides the functionality of terminating the launched activity, releasing the activity object and destroying it at the end of the test flow after all methods annotated with @After are finished.
  • Is always used with the @Rule annotation (provided by JUnit)

When used with @Rule annotation, the activity under test is launched before each test annotated with @Test and before any method annotated with @Before. It’s terminated after the test is completed and all methods annotated with @After are finished.

In the sample code given below, the activity coded in ‘MainActivity.class’ is launched and stored in the object variable ‘mActivityTestRule’. At the end of the test, the activity is closed, and the object is released and destroyed.

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

Note: This class is deprecated.
use ActivityScenario or ActivityScenarioRule instead. They offer a simpler, and safer way of controlling Activity lifecycles.

ActivityScenarioRule launches a given activity before the test starts and closes after the test.

You can access the ActivityScenario instance via getScenario(). You may finish your activity manually in your test, it will not cause any problems and this rule does nothing after the test in such cases.

@Rule
public ActivityScenarioRule rule = new ActivityScenarioRule<>(MyActivity.class);

@Test
public void myTest() {
ActivityScenario scenario = rule.getScenario();
// Your test code goes here.
}

ActivityScenario provides APIs to start and drive an Activity’s lifecycle state for testing. It works with arbitrary activities and works consistently across different versions of the Android framework.

Before we proceed any further, there are three more classes from the library ‘androidx.test.espresso’ that we need to get a little familiar with. They are the Espresso class, the ViewInteraction class and the DataInteraction class

The Espresso class:

  • It is considered as the actual entry point into the Espresso framework.
  • The beginning of test execution creates an Espresso object.
  • Its Primary purpose is to create a special type object, called interaction object, which are capable of interacting with the android UI elements(views) in an android activity(screen)
  • Its onView() method is used to create and return a ViewInteraction object which, in turn, contains methods that lets the developer interact with a specific view. Syntax: ViewInteraction objViewInteraction = Espresso.onView(<A Matcher object returned by one of viewMatchers class’ methods>)
  • Espresso’s onData() method is used to create and return a DataInteraction object which, in turn, contains methods that lets the developer interact with a specific view that can be considered as a data object rather than a visual UI object for logical and interactive purposes (Eg: List of values in a dropdown, grid of values in a web table, etc)

The ViewInteraction class:

  • Provides us with the methods for two most basic UI interactions required for performing any UI based tests namely:
  • perform() method to simulate a user input action on the view such as tap, swipe, text entry, etc. Syntax: objViewInteraction.perform(<A viewAction object returned by one of viewActions class’ methods>)
  • check() method to compare the actual state of the view with its expected state. Syntax: objViewInteraction.check(<A viewAssertion object returned by one of viewAssertions class’ method>)

The viewMatchers class:

  • Contains static methods that can be used to create and return a Matcher object — a hamcrest-framework-based object that represents a mechanism to uniquely match a view in an activity.
  • Is defined in androidx.test.espresso.matcher library.
  • Commonly used methods are: withId(int <id>), withResourceName(String <name>), withText(String <text>)

Here is a sample code that uses viewMatchers class’s withText() method find a view which contains the text, “Hello World!” and return a matcher object, that uniquely represents a view, as a parameter to the onView().

ViewInteraction viewInteraction = Espresso.onView(withText("Hello World!"));

This viewInteration object can later be used to invoke it’s perform() or check() method to do an action or validation, respectively.

The viewActions class:

  • Contains static methods used to create and return a viewAction object — an object that represents a specific mechanism to perform an action on a view.
  • Is defined in androidx.test.espresso.action library
  • Commonly used methods are: typeText(String <text>), cleartext(), swipeUp(), swipeDown(), swipeLeft(), swipeRight(), click(), doubleClick(), longClick()

Once the onView() method has created a viewInteraction object, any action can be invoked by calling the perform() method of that object. The viewAction object, which is returned by one of the viewActions method, is passed as a parameter to the perform() method.

Here is a sample code to click the “Hello world!” view. The click action of the matched view will be executed.

ViewInteraction viewInteraction = Espresso.onView(withText("Hello World!")); viewInteraction.perform(click());

The viewAssertions class:

  • Contains static methods that can be used to create and return a viewAssertion object — an object that represents a specific mechanism to compare the state of a view on the application (actual) with a view that’s defined in the test script(expected).
  • Is defined in androidx.test.espresso.assertion.ViewAssertions library
  • The most commonly used method is check(<Matcher object>)

Once the onView() method has created a viewInteraction object, any validation can be done using the check() method. The viewAssertion object returned by one of the viewAssertions method is passed as a parameter to the check() method.

Here is a sample code to validate the whether a matching view is present on the application’s activity based on its resource ID:

// Fetching Mobile object using onview method
ViewInteraction viewInteraction = Espresso.onView(withText("Hello World!"));
// performing Match operation on Mobile Test object
viewInteraction.check(matches(withId(R.id.text_view)));

Now let’s put together all what we have learnt and see the whole picture of how an Espresso test runs.

=> Before starting the test execution, the developer needs to take care of the following:

  1. The class containing the espresso test cases needs to be annotated with @RunWith(AndroidJUnit4.class).
  2. Espresso needs at least a single JUnit rule of type ActivityTestRule to specify the activity.
  3. Every test class needs a minimum of at least one onView() or onData () method invocation to match and find the desired view.

=> To commence the automated test execution, AndroidJUnit4 runner (JUnit runner for Android) will prepare the environment. Environment preparation tasks include:

  1. Starting either the connected android device or emulator
  2. Installing the app to be tested and making sure the app is in test-ready state.

=> Once the environment is ready, AndroidJUnit4 runner will start running the tests. The test run tasks include:

  1. Launching the activity to be tested using ActivityTestRule.
  2. Getting the ViewInteraction object returned by onView() or onData() method
  3. Simulating a user input action on the actual view using the perform() method of the viewInteraction object
  4. Validating the actual state of the view by comparing it with the expected state of the view using the check() method of the viewInteraction object.

The flow diagram below, gives a visual representation of the whole process.

Espresso workflow

--

--