The Basics of Android Espresso Testing: Activities & Fragments

Amr Yousef
AndroidPub
Published in
4 min readJun 19, 2017

--

There comes a point in your software developer journey where you realise that unit testing is really important. This especially happens if you want to make sure that your code still works after you do some changes.

In Android, there are two types of tests:

  1. JUnit Tests
  2. Android instrumented unit test

This article focuses on the latter. Espresso testing framework is usually used to automate UI testing with the help of AndroidJUnitRunner test runner. Other libraries also exist such Robolectric.

Firstly, assuming that you have an android project ready, add the below extra gradle dependencies:

Testing Grardle Dependencies

Gradle will make sure you compile the needed libraries when you are compiling the test version of your project. The last dependency is a light-weight mock web-server which you can use to test networking code.

Another thing to add is a reference to the test runner:

Test Runner Reference

We are going to test an application which has one activity with the following:

  1. Text view
  2. Floating action button
  3. Snackbar
App Skeleton

As mentioned before, we are going to focus on android instrumented tests, so go to your java folder, expand it and expand the folder with (androidTest).

Now let’s get familiar with the Espresso API!

Create a new Java class, name it — in this case, I named it TestMainAcitivty, then open it. You will notice that I added “@RunWith(AndroidJUnit4.class)” to the code.

package com.example;@RunWith(AndroidJUnit4.class)
public class TestMainActivity {
}

The @Runwith annotation will tell the JUnit to run the tests in this class using the Android JUnit test runner.

Now we are testing the MainActivity, so we can say that to JUnit by using the @Rule annotation and providing a Test Rule:

package com.example;@RunWith(AndroidJUnit4.class)
public class TestMainActivity {
@Rule
public ActivityTestRule<MainActivity> activityActivityTestRule = new ActivityTestRule<MainActivity>(MainActivity.class);
}

The Rule will make sure to launch the MainActivity directly. This means that when testing an n-layer activity, you don’t need to do all the steps to start it. Simply define that in the rule and you are ready to go.

In this example, we don’t use fragments but I am sure every android developer out there uses them and if you’re wondering how to open a fragment at this point, well it’s pretty easy. All you have to do is to tell the JUnit that you need to perform an operation first before running your tests. This is done by making a function, let’s call it “init()”, and annotating it with @Before annotations.

To change the fragment, you need to get the fragment manager and in order to do that, you need to get the activity. All this can be done using the rule object we created:

...
@Before
public void init(){
activityActivityTestRule.getActivity()
.getSupportFragmentManager().beginTransaction();
}
...

It’s worth mentioning that for the sake of demonstration, I made the fragment change before running the test. However, you can still do the fragment change inside your test function.

By this point, we have the Activity and a selected fragment up and running before executing our test. Now let’s see how to actually make a test.

Let’s say I want to:

  1. Test that my text view is visible
  2. Write 3 letter in the text view

So here we go…

Create your test function and annotate it with @Test which will tell JUnit that this is a test.

...@Test
public void TestAutoComplete(){
}
...

To select a view, Espresso framework has a function called “onView()” and to state that we want to select it by its id, we use “withId()”

onView(withId(R.id.content_main_start_text))

We also want to do some checks on it first so we use check():

onView(withId(R.id.content_main_start_text)).check()

In this case, our check is that the view is visible, which means that the view visibility matches visible (displayed state):

onView(withId(R.id.content_main_start_text)).check(matches((isDisplayed())));

If the view is displayed, we want to type 3 letters as mentioned:

onView(withId(R.id.content_main_start_text)).perform(clearText(),typeText("Amr"));

We select the view as before, but instead of using “check()” we use “perform()” because we want to perform some actions on the view. The actions were; clear any previous text “clearText()” and typing “Amr” using “typeText()”.

In the example app I also have a floating action button that if I click will show a Snackbar. To test this, I added another function similar to this:

...
@Test
public void TestFab(){
onView(withId(R.id.fab)).perform(click());
onView(allOf(withId(android.support.design.R.id.snackbar_text), withText("This Test Works")))
.check(matches(isDisplayed()));
}
...

The major difference here is that in the second “onView()” call, I passed two ViewMatchers instead of one, the id, to make sure that I am matching a piece of text on a certain view which is the Snackbar text.

If you launch your Activity with some Extras, you can test that by modifying the Rule. Here is an example:

@Rule
public ActivityTestRule<MainActivity> mainActivityActivityTestRule = new ActivityTestRule<MainActivity>(MainActivity.class){
@Override
protected Intent getActivityIntent() {
Intent intent = new Intent(InstrumentationRegistry.getContext(),MainActivity.class);
intent.putExtra("Key","Value");
return intent;
}
};

If you have a RecyclerView and you want to click on its items, add the Espresso contrib dependency to your build.gradle:

androidTestImplementation('com.android.support.test.espresso:espresso-contrib:2.2') {
exclude module: 'support-annotations'
exclude group: 'com.android.support', module: 'appcompat'
exclude group: 'com.android.support', module: 'support-v4'
exclude module: 'recyclerview-v7'
}

And call it as below:

onView(withId(R.id.content_main_start_text)).perform(        RecyclerViewActions.actionOnItemAtPosition(0, click()));

--

--