How to Do TDD in Android — Part 4: Espresso & UI Tests
In this final post of the TDD in Android series, we’ll cover UI testing with Espresso.
To recap: we’ve covered project setup in Part 1, unit tests in Part 2, and mocking with integration tests in Part 3. Now for UI tests.
What is Espresso?
Espresso is Google’s framework for UI testing. It gives you an API to test the UI of an Android app without user intervention. It’s built around three core objects:
- ViewMatcher — finds a view in the UI using
onView() - ViewAction — simulates interactions via
ViewInteraction.perform() - ViewAssertion — verifies view state using
ViewInteraction.check()
onView(withId(R.id.my_view)) // ViewMatcher
.perform(click()) // ViewAction
.check(matches(isDisplayed())); // ViewAssertion
Official Espresso cheat sheet: https://developer.android.com/training/testing/espresso/cheat-sheet.html
Setup
Verify Espresso is in your build.gradle:
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
Create LoginActivityTest:
@RunWith(AndroidJUnit4.class)
public class LoginActivityTest {
}
Writing UI tests
Every test needs an ActivityTestRule:
ActivityTestRule<LoginActivity> activityTestRule =
new ActivityTestRule<>(LoginActivity.class);
Check the username field is visible:
@Test
public void checkUserNameEditTextIsDisplayed() {
activityTestRule.launchActivity(new Intent());
onView(withId(R.id.txt_user_name)).check(matches(isDisplayed()));
}
Check the password field is visible:
@Test
public void checkPasswordEditTextIsDisplayed() {
activityTestRule.launchActivity(new Intent());
onView(withId(R.id.txt_password)).check(matches(isDisplayed()));
}
If you change isDisplayed() to its inverse and run the test, it will fail — a good sanity check.
Verify the error message when submitting empty fields:
@Test
public void checkErrorMessageIsDisplayedForEmptyData() {
activityTestRule.launchActivity(new Intent());
onView(withId(R.id.btn_login))
.check(matches(isDisplayed()))
.perform(click());
onView(withText(R.string.error_user_password))
.check(matches(isDisplayed()));
}
Verify successful login:
@Test
public void checkLoginSuccess() {
activityTestRule.launchActivity(new Intent());
onView(withId(R.id.txt_user_name))
.perform(typeText("user"), closeSoftKeyboard());
onView(withId(R.id.txt_password))
.perform(typeText("password"), closeSoftKeyboard());
onView(withId(R.id.btn_login))
.check(matches(isDisplayed()))
.perform(click());
onView(withText(R.string.login_ok))
.check(matches(isDisplayed()));
}
Note: UI tests require a physical device or emulator to run.
The project is complete — and fully tested at every level. Now it’s time to apply this in your own projects.
Full source code (Java): https://github.com/jamontes79/TDD_Ejemplo
Kotlin version: https://github.com/jamontes79/TDD_Ejemplo_Kotlin
Hope you found this series useful. Any feedback is welcome.