Android Espresso — More than just a coffee ;)
Apps UI Tests in a nutshell
1. Intro to UI testings
Part of the process of building an app is to check that the features you’ve implemented work as expected. For example: clicking a button on the screen and verifying the expected image appears.
One of the most apparent types of testing is User Interface Testing, or for short UI Testing. It means testing the components on the screen that the user can interact with.
Android Studio provides a powerful tool called Espresso to help us as developers efficiently UI test the apps we make. Espresso is a testing framework that includes a set of APIs that simulates and schedules user interactions to help us as developers test an app’s user interface automatically.
Most of the app we use have a lot of user interface components. We need to make sure that all the touch points in our app make a good user experience being seamless and functions as anticipated.
Espresso allows developers to automate the testing process so that it can be tested at scale and much more efficiently.
Steps to manually UI test:
(1) Find the view
(2) Perform action on the view
(3) Check if the view does what you expected
These are the building blocks for writing tests in Espresso.
Steps to UI test in code:
(1) onView(ViewMatcher*) => onView(withId(R.id.send_button))
(2) .perform(ViewAction) => .perform(click())
(3) .perform(ViewAssertion**) => onView(withId(R.id.sent_text).check(isDisplayed())
*ViewMatcher — A class that helps us specify the view we’re interested in the current view hierarchy. The matches come from the Hamcrest Matcher library, which is a compilation of possible ways to help us identify a view matches what we’re expecting using human-readable language.
** Assertion — A check to see if what we expected matches what actually happened. ViewAssertion is a class with methods that help us perform assertions (or checks) on views.
Altogether it’s the single compilation of statement we will use to execute the UI test in Espresso. The process is meant to mimic the human testing of the UI and be straightforward to use.
We should always follow this steps: Match the view, act on the view and then assert what we expect to happen.
Instrumented Test — This lesson will focus on User Interface (UI) Tests which are a type of Instrumented Tests. Instrumented Tests need to be run on a physical device or emulator. There are a number of other types of tests available as well, such as Unit Tests that run on the Java Virtual Machine of the PC. Instrumented Tests are always located under module-name/src/androidTest/java/
In that test file, we can add a @Rule and a @Test. ActivityTestRule is a rule that provides functional testing for a specific, single activity.
Espresso is helpful for testing: Views, AdapterViews, Intents and Idling Resources.
Idling Resources are used when testing any asynchronous code, for example: long-running database operations that are off the main thread.
2. AdapterViews Testing
While onView() can handle most Views in our UI, Espresso does require a different method call when dealing with AdapterView widgets. Since AdapterViews such as ListView and GridView load data dynamically from an Adapter, only a subset of the contents may be loaded in the current view hierarchy at a time. This means that onView() may not be able to find the necessary view.
To handle this we need to use onData() which loads the adapter item we are interested in onto the screen before operating on it.
To help us further specify the item in the AdapterView we’re interested in, we can use a DataOption method such as inAdapterView() or atPosition().
After that, we perform an action and then check that we get the desired result on the view that we’re interested in.
We test Views in AdapterViews is very similar to how we test single Views — matching, acting, and asserting.
To find data in AdapterView:
To find data in views:
3. Intent Testing
Intent testing divided to two:
(1) Intent Stub — A small piece of code that acts as a fake response to an intent call during a test. The benefit of using a stub is that it gives us consistent results and allows us to focus on testing just one action at a time (For example: checking an interface). We use a stub or a canned answer that we can use to do the test. Intent stubbing is useful for testing intent responses. In code: intending(Matcher<Intent> matcher. How to code the test: (a) @Rule — use IntentsTestRule instead of ActivityTestRule (b) @before — stubbing an intent must be set up each time a test is run and we need to make sure all external intents are blocked. In android 6 (M) and later on we also need to grant for permission. (c) @Test — An example: intending(hasComponent(hasShortClassName(“.ContactsActivity”))).respondWith(new ActivityResult(Activity.RESULT_OK, ContactsActivity.createResultData(VALID_PHONE_NUMBER)));
(2) Intent Verification — Helps us to make sure that the information that was intended to be sent was what actually sent, by using a hardcoded matcher. In code: intended(Matcher<Intent> matcher, VerificationMode verification). How to code the test: (a+b) Check out intent stubs steps (c)@Test — An example: intended(allOf(hasAction(Intent.ACTION_CALL), hasData(INTENT_DATA_PHONE_NUMBER), toPackage(PACKAGE_ANDROID_DIALER)));
4. Idling Resources Testing
In order to account for the time it takes for async background work to happen, we need to implement idling resources, which has a time delay that allows us to wait for the async background work to finish before continuing the test. In that case, Espresso will pause testing until the background tasks are done.
Espresso waits until the app is idle, or not doing anything, to perform the next action. It’s idle if there are no UI events in the current message queue, and there are no more tasks in the default AsyncTask thread pool.
IdlingResource is an interface that requires to implement the following methods:
To run a test that involves idling resources we will need to register the idling resource (Espresso.registerIdlingResources()) before the test is run using a @Before method. What happens at the @Before block occurs after the activity is created. We need to make sure that the idling resource is registered before the async task.
After the test, we need to unregister the idling resource (Espresso.unregisterIdlingResources()) in our @After annotation. We do so that we don’t cause any issues if the idling resource needs to be used elsewhere in the future.
To make Idling resources work, we must not forget to add its matching dependency in the gradle file.
5. More Tests
Espresso holds more test components then Views, AdapterViews, Intents and Idling Resources. More test options available in Espresso:
(1) Espresso Web — An API for writing automated tests for apps that contain one or more WebViews. Espresso Web reduces the boilerplate code needed to interact with these WebViews.
(2) Espresso for RecyclerViews — Espresso testing for RecyclerViews works differently from testing AdapterViews. It doesn’t use onData(); instead, has actions that scroll to positions or perform actions on items.
(3) Espresso Test Recorder — Allows you to create UI tests by simply recording your interactions on a device and the Test Recorder will auto-generate the test code for you!
Different kinds of tests:
(1) Instrumented Unit Tests — These are tests that must be run on an Android device or emulator because they depend on the Android framework (like: UI tests). Instrumented tests run using the AndroidJUnitRunner which controls launching the app and running UI tests on it. Instrumented Tests live under module-name/src/androidTest/java/
(2) Local Unit Tests — Local Unit Tests are Unit tests that are only run on the local Java Virtual Machine and don’t necessarily depend on the Android framework. We will use the JUnit testing framework for Java to just test that local test. Local Unit tests live under module-name/src/test/java/. JUnit is a framework used to test discrete pieces of code (usually methods). Android provides JUnit testing support via the AndroidJUnit Test Runner.
(3) Android Testing Support Library — Espresso is just one test automation tool provided by the Android Testing Support Library. This Library also includes the followings:
(a) AndroidJUnit — A test runner that runs JUnit style tests on Android devices. When used in Espresso tests, it controls launching the app and running UI tests.
(b) UI Automator — Framework for cross-app functional UI testing between the system and installed apps.
(c) Espresso — Framework for functional UI Testing
You can find much more at the free course Advanced Android App Development by Google on the Udacity website over here: (check it out!)