Introduction

The development of Android Apps and the development of Java / JEE Applications do not differ much. The programming language is Java and the ADK (Android Development Kit) implements many of the functions the JDK (Java Development Kit) offers. Furthermore you can add libraries to your build configuration in order to reuse existing functionalities. But as soon as you are concerned with writing apps in a professional manner, one recognizes that it is hard to achieve a solid test coverage. As a software developer I have developed an understanding of building software with a certain quality, that fulfills the means of testability and a high automation level. When I first started with developing apps, I always met the same development cycle:

  • development of a feature
  • deployment to device
  • manual testing
  • fix of wrong implementation
  • deployment to device and so on…

So how do you automatize such an inelegant mobile development process? How can you reduce your manual testing effort? Well, you can start doing what every software developer should do: Start writing tests.

In this blog post I am going to explain, how you can use the Espresso Testing Framework in your Android application development and how it helps to reduce the overhead of manual testing.

What is the Espresso Framework

Testing user interactions within a single app helps to ensure that users do not encounter unexpected results or have a poor experience when interacting with your app. You should get into the habit of creating user interface (UI) tests if you need to verify that the UI of your app is functioning correctly. (Android Developer)

Espresso is targeted at developers, who believe that automated testing is an integral part of the development lifecycle. While it can be used for black-box testing, Espresso’s full power is unlocked by those who are familiar with the codebase under test. (Android Testing Support Library)

As quoted above, the Espresso Framework is used to mimic the user input on the UI. With the use of the Espresso Framework you can perform manipulations on the UI and afterwards assert the correct outcome of your input with a JUnit 4 Syntax. Also it is possible to ensure that certain UI elements are being loaded and displayed to the UI. Those tests can be executed automatically during the app-build phase, or as standalone test. The Espresso Framework can be categorized as a standard black-box test, with knowledge about the layout, such as IDs of the UI elements, and no knowledge of the Code that stands behind the UI functions.

Prerequisites

Running Espresso tests requires some infrastructure, such as an IDE like Android Studio and a device to execute the tasks, The device which can be some physical connected device or an emulator.

How to setup the Espresso Framework

In the following I will explain how to add the Android Espresso Framework to your android application using Android Studio and Gradle.

At first add the AndroidJUnitRunner to your default config in the build.gradle file. Then you will need to add the Espresso dependencies to your build.gradle file:

After this step you should check if the package can be build with the current configuration. If you encounter an error with this configuration, stating something like you used a duplicate dependency with different version numbers for the app-target or test-target in your build file, then you have to decide for yourself which version of the dependency you will use. General practice is, to exclude the dependency that causes the problem from the test-target. The following example shows how to exclude the dependencies for support-annotations from the test-target:

As soon as your build succeeds, this step is finished.

Writing your first Espresso Test

After adding all required dependencies to the build.gradle, you can start to write your first test. A good starting point is to test your initial layout that is being loaded after starting the app.

We start off with adding a new testclass to the package labeled with androidTest. In Android Studio 2.0 this looks like the following Screenshot:

2016-04-26_16h41_30

“planningPoker” is the name of the App-Module I am using. Here you have to navigate to the src/androidTest/java folder and after a right click on the java folder select New/Java Class.

Prior to Android Studio 2.0 you might not be able to see this package. In order to solve this, you might have to switch the build variant of your Test Artifact in Android Studio to Android Instrumentation Tests. The following code-snippet shows the standard layout of an Android Espresso Test:

Here we see the basic characteristics that you need to know about in an Espresso Test.

Characteristics

The following lines describe the characteristics of an Android Espresso Test.

By using the @Rule ActivityTestRule the framework helps you with the initial setup of your test. As commented inline you can pass the entry point of your app as first parameter. Every activity that is  defined in your manifest file can be selected as entry point. The second parameter lets you decide whether to use touch mode or focus mode in your instrumentation, whereas true defaults to touch mode. Finally the third parameter lets you decide whether your requested activity shall be started automatically at the beginning of each test, or manually. When you select false as third parameter you can modify the bundle parameters that are being passed to the activity at startup.

After setting up the test rule we must load at least the target context in the @Before method of the test, because it will be needed later on during the test executions.

Writing the first assertion

This part is finished off by writing the first assertion, in which it is checked that a view is correctly loaded and displayed in the UI.

The structure of the assertion is easy to remember: By using method chaining we will first need a ViewMatcher on which a ViewAssertion is applied and finally a ViewAction can be applied.

  • ViewMatcher (onView)
  • ViewAssertion (check)
  • ViewAction (perform)

R.id.your_view_id is the resource identifier you want to check in your initial layout class.

How to execute the tests

To avoid flakiness, we highly recommend that you turn off system animations on the virtual or physical device(s) used for testing.

  • On your device, under Settings->Developer options disable the following 3 settings:
    • Window animation scale
    • Transition animation scale
    • Animator duration scale

https://google.github.io/android-testing-support-library/docs/espresso/setup/index.html

The reason for disabling these animations is, that Espresso can not wait until the animation is finished. So if you are executing a, for example, Transition between Activites, Espresso expects the Activity already being loaded and continues its work. In this case you may experience a view not found exception depending on the length of the animation.

Before: 2016-04-26_17h15_23 After: 2016-04-26_17h15_58

After you ensured that the settings are being made as quoted above, you should create a new run configuration, in order to execute the tests. In Android Studio you open the Run menu and click on Edit Configurations. The second step is to add a new Android Tests configuration. Here you will have to choose a module and add the instrumentation runner you added previousely (android.support.test.runner.AndroidJUnitRunner). Save the dialog and execute the newly created Run configuration.

  1. confluence_1
  2. confluence_2
  3. confluence_3

The three parts of Espresso Interactions

The following describes the three basic parts that an Espresso interaction consists of.

ViewMatcher

A ViewMatcher identifies the target view. By using the expression onView(allOf( {…} )), selectors on the loaded layout are applicable. You can always use that selector unless you want to interact with data that is hosted in an AdapterView. To interact with data you must use the expression onData(allOf( {…} )). The two expressions differ in their type. As onView is of type ViewInteraction and onData is of type DataInteraction, the applicable commands which follow these methods differ between those two. To finally match a view, a selector must be applied in the placeholders {…}. Here you can use the Espresso selectors withId() and withText(). Additionally you can use standard HamcrestMatchers and even write your own ViewMatcher.

ViewActions

After specifying the view we can use further methods on the returned ViewInteractions and DataInteractions using method chaining. These two allow us to interact with the UI by executing methods that are defined in the Class ViewActions of the Espresso framework. The following is a list of the most common interactions:

  • ViewActions.click()
  • ViewActions.doubleClick()
  • ViewActions.longClick()
  • ViewActions.enterText()
  • ViewActions.clearText()

If the interactions provided by the ViewActions class do not fit your needs, you can still implement your own ViewAction. The important part of your custom ViewAction is, that the perform() Method must return an object of type ViewInteraction or DataInteraction.

ViewAssertion

As we are within a test scope we finally want to use assertions on our UI. Via the method ViewInteraction.check( {…} ) and DataInteraction.check( {…} ) we can perform assertions on the objects of our ui. A basic example of a ViewAssertion is the expression onView(withId(R.id.okbutton).check(matches(withText(“OK”)); . This assertion checks that the button okbutton has the text OK. Here you can use every hamcrest matcher you can get hold on in the check() method. Again, you can also write your own custom matcher.

DataOptions

Actually there is a fourth part of Espresso interactions. It is called a DataOption and is only used with onData() method calls. You can use it to specify the AdapterView you are expecting. Common methods used as DataOptions are:

  • onAdapterView
  • atPosition
  • onChildView

Advanced Examples

The following lists some more advanced examples of how to use the Espresso framework.

Layoutinteraction on an AdapterView

The code example listed above shows, how to perform a click action on a ListItem that contains the text How To. This also demonstrates the concatenation of multiple ViewMatchers.

Mocking of outgoing Intents

As Espresso is very capable of interacting with an application that you wrote yourself, outgoing Intents and calls to other applications exceeds the capabilities of the Espresso framework, because you would leave the scope of the test. But do not worry, Espresso has a way of handling these Intents by using the extension library Espresso Intents. Espresso Intents offers the ability to set the result of an outgoing api call and also check the outgoing Intent on correctness. The following example shows, that the result of the Intent is already defined before the user-interaction using the method intending( {…} ). If you have multiple possible outgoing Intents, you can specify the mock on e.g. the type of IntentAction that will be used, or the data you are expecting to be transported. After mocking the result we can execute the user-interaction. Finally we can check the outgoing Intent on correctness using the method intended( {…} ).

It is also important, that the ActivityTestRule must be changed into an IntentsTestRule. Both rules are similar, the only difference being, that IntentsTestRule enables the mocking of Intents. The following shows how to setup of an Espresso Test looks like when using Espresso Intents.

Waiting for asynchronous calls

When you are developing a mobile application, it is common to load data from a webserver. A basic example is an IntentService, that is used to load data. Espresso has the ability to wait for UI events and AsyncTasks before the next testing operation is executed. So how do you wait until your data is being loaded when using Services, while executing an espresso test? For this use case Espresso offers the usage of so called IdlingResources.

IdlingResource

So what do you have to keep in mind when you are implementing a custom Idling Resource?

Implementing the IdlingResource

At first you must implement the IdlingResource Interface, so that your custom IdlingResource is recognized as one. The most tricky part is the isIdleNow() method. Here the logic on whether the resource is busy or not must be implemented.

Register the custom IdlingResource

Your custom IdlingResource must be registered to the Espresso framework before you start with your test execution. This means you must initialize it in the @Before method of your test and call Espresso.registerIdlingResources(…). Actually you will also have to remove your custom IdlingResource after the test execution in the @After method of your test.

Custom Click Action

Sometimes when writing an Espresso Test, with a click action on an ImageView, it may occur that it fails with the following errormessage:

If this happens, you have two choices:

  • Check and correct your layout file
  • build your own Custom Click Action

The first choice is the most common one. It can be applied to nearly all of your usecases. But in case you rely on a dynamically loaded image from webresources, or your view is not visible at least 90% by design, you may have to overwrite the 90% rule. What you can do now is writing that Custom Click Action by fetching the code of the google developed click action and paste that code into a new class. Be aware that you will also have to copy the copyright documentary header of that class. Finally you will have to just change one single line:

The complete class is listed below as attachment.

Custom View Matcher

When working with ListViews and Objects you may encounter the problem that a standard Hamcrest Matcher won’t be any help in selecting the desired view. Luckily there exists the possibility of creating your own Custom ViewMatcher. The following listing gives you an example of a matcher that matches the String description of the class ListItem.


The characteristics of a ViewMatcher are:

  • the return value must be of type Matcher
  • Parameters must be of type Matcher<?>.
  • In this case a  BoundedMatcher is returned. A BoundedMatcher only works with elements that are a specific subtype of this matcher.
  • BoundedMatcher must override the two methods describeTo and matchesSafely.
    • describeTo prints a readable error in case the matcher does not match any view.
    • matchesSafely is the logic to match the item to the desired input.

Another example of how you can use a Custom View Matcher is the following ListViewMatcher. It asserts that a given ListView has at least the size that is passed in.

The Custom Matchers can be applied in just the same way as the preconfigured matchers are applied to the views.

Attachments

Sources

Leave a Comment

2 comments

  1. A

    Great article .. thanx Dirk!

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close