Android App UI testing with Espresso

Getting bored to run the same UI flow again and again for testing? Try using Espresso.

SHISHIR
5 min readOct 14, 2018
Image result for UI testing image android espresso

Before Started

Before starting we will know about Testing. Android has mainly two types of tests. Unit Tests and Instrumentation Tests.

Unit Tests

  • Often Unit test referred to as ‘Local Test’ or ‘Local Unit Test’.
  • This is used to test every method/function our code.
  • Unit Test runs in the JVM local machine without the need of an Emulator or Device.
  • Unit Tests run much faster compare to the time required to run test on an Android device (Instrumentation Test).
  • Unit Test can not test the UI for your app without mocking objects such as an Activity.

Instrumentation Tests

  • Instrumentation Tests are used for faster testing Android frameworks such as UI, SharedPreference and so on. It can also be used to test none UI logic as well.
  • Instrumentation Test runs on a device or emulator.
  • This test use a separate apk for the purpose of testing.(Thus, every time a test case is run, Android Studio will first install the target apk on which the tests are conducted. After that, Android Studio will install the test apk which contains only test related code.)

Espresso Basics

  • Espresso is one of the most commonly used an Instrumentation Testing framework for Android Applications.
  • This was made by Google for the ease of UI Testing.
  • Google released this framework in Oct. 2013. Since its 2.0 release Espresso is part of the Android Support Repository.
  • Espresso automatically synchronizes your test actions with the user interface of your application. The framework also ensures that your activity is started before the tests run. It also let the test wait until all observed background activities have finished.

Espresso has basically three major components:

1. ViewMatchers — allows to find view in the current view hierarchy. Simply it refers to "find something".2. ViewActions — allows to perform actions on the views. Simply it refers to "do something".3. ViewAssertions — allows to assert state of a view. Simply it refers to "check something".

Here is the General rule for Base Espresso Test

onView(ViewMatcher)          -- finds the view
.perform(ViewAction) -- perform an action on the view
.check(ViewAssertion); -- validates an assertion

If Espresso does not find a view via the ViewMatcher, it includes the whole view hierarchy into the error message. That is useful for analyzing the problem.

There is a cheat sheet for espresso you can use for a quick reference while development. Th sheet contains frequent available View Matcher, View Action and View Assertion instances.

Make Espresso Ready in your App

  • Use the Android SDK manager to install the Android Support Repository.
  • Add the following dependency to the Gradle build file of your project.
  • Add android.support.test.runner.AndroidJUnitRunner as value for the testInstrumentationRunner parameter in android.defaultConfig in the same build.gradle file.
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

{ AndroidJUnitRunner is the instrumentation runner. This is essentially the entry point into running your entire suite of tests. It controls the test environment, the test apk, and launches all of the tests defined in our test package}

  • Exclude LICENSE.txt Via the packagingOptions, depending on the libraries you are using.
  • Turn off system animations on the virtual or physical devices used for testing (Animations may complicate the test cases). On your device, under Settings > Developer options, disable the following 3 settings:
  1. Window animation scale
  2. Transition animation scale
  3. Animator duration scale

Some Annotations Used in Espresso

There are 6 types of annotations that can be applied to the methods used inside the test class,which are @Test, @Before, @BeforeClass, @After, @AfterClass, @Rule.

@BeforeClass:

Method annotated with this will run first and only once.

@Rule:

Prove functional testing of a single activity. U can access the activity using the rule and thereby can access the Resources etc.

@Before:

Method annotated with this will be run before every tests for eg: if there are two tests this method will run two times.

Can be used for setting up pre-condition that need s to executed before executing the test case class.

@Test:

Methods marked with @Test are run after the @Before methods.

@After:

Method annotated with this will be run after every tests for eg: if there are two tests this method will run two times.

Can be used for resetting a variable after the test.

@AfterClass:

Method annotated with this should be static, will run last and only once.

Annotation can be used to execute a method that needs to be executed after executing all the tests in a JUnit Test Cases class.

Important things to note is that

  • The activity will be launched using the @Rule before test code begins
  • By default the rule will be initialised and the activity will be launched(onCreate, onStart, onResume) before running every @Beforemethod
  • Activity will be Destroyed(onPause, onStop, onDestroy) after running the @After method which in turn is called after every @Test Method
  • The activity’s launch can be postponed by setting the launchActivity to false in the constructor of ActivityTestRule ,in that case you will have to manually launch the activity before the tests
Note:You can have more than one method annotated with any of the annotations like @Before,@Beforeclass etc. But the order in which JUnit finds methods is not guaranteed.Like if there is two methods annotated with @Before, There is no guarantee which one will be executed.

Now it is time for Coding

  • Add the following static imports to simplify the usage of the Espresso. This allows to access these methods without the class prefix.
  • Espresso tests must be placed in the app/src/androidTest folder. In order to test a UI create a new test class in the Location
module-name/src/androidTest/java/
  • And annotate it with @RunWith(AndroidJUnit4::class)

* Test Case to check Login success:

    String userName = "shishir13";
String password = "password";

onView(withId(R.id.userNameEt))
.perform(typeText(password),closeSoftKeyboard());

onView(withId(R.id.passwordEt))
.perform(typeText(password),closeSoftKeyboard());

onView(withId(R.id.loginButton))
.perform(click());
onView(withId(R.id.login_success_tv))
.check(matches(withText("login_success")));

** Test Case for User Signup:

No need to register user manually; This will do the magic for you.

    String userName = "shishir13";
String userEmail = "shiktoshishir15@gamil.com"
String password = "password";
String confirmPassword = "password";
onView(withId(R.id.userNameEt))
.perform(typeText(userName),closeSoftKeyboard());
onView(withId(R.id.userEmailEt))
.perform(typeText(userEmail),closeSoftKeyboard());
onView(withId(R.id.passwordEt))
.perform(typeText(password),closeSoftKeyboard());
onView(withId(R.id.passwordEt))
.perform(typeText(confirmPassword),closeSoftKeyboard());
onView(withId(R.id.signUpButton))
.perform(click());
onView(withId(R.id.sign_up_success_tv))
.check(matches(withText("signup_success")));

** Test Case to show Greeting Message on Next Activity:

That is how you can talk to other activities.

    onView(withId(R.id.userNameEt))
.perform(typeText("Shishir_13"),closeSoftKeyboard());

onView(withId(R.id.goToNextActivity))
.perform(click());
onView(withId(R.id.greeting_message_tv))
.check(matches(withText("Welcome Shishir_13")));

** Test Case to check if matched item is selected or Not

The following test case demonstrates that how to work with ListView, Gridview, Spinner, and other Adapter based views.

    onView(withId(R.id.spinnerID))
.perform(click()); // Perform click on spinner
onData(allOf(is(instanceOf(String.class)),
is(COUNTRY).perform(click());
onView(withId(R.id.selected_country))
.check(matches(withText("selected" + COUNTRY)));

** Test Case to perform click operation on RecyclerView

Recyclerview is a UI Component designed to render a collection of data just like listView,GridView. You can perform actions on it by passing position as parameter.

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

** Test Case to work with AutoCompleteTextView

     onView(withText("AutoCompleteText"))

.inRoot(withDecorView(not(is(getActvity().getWindow().getDecorView()))))
.check(matches(isDesplayed()));

To Avoid Exceptions !!

  • Use unique id for every view.
  • Be sure the id is present on the view.
  • Invalidate cache and restart Android Studio while altering test case.

Thank for reading this article. Be sure to give claps if you find this article to be helpful. Thanks for reading.

Happy Coding :)

--

--

SHISHIR
SHISHIR

Written by SHISHIR

{ 'designation' : 'Lead Software Engineer' , 'hobby' : [ 'Music', 'Photography', 'Travelling' ] ,’email’: ‘shishirthedev@gmail.com’ }

Responses (1)