Starting with ESPRESSO

Sri Vishnu S
android-core
Published in
4 min readMay 11, 2020

What is Espresso?
(Definitely, it is not about COFFEE) So then what is it, espresso is a user interface testing framework developed by Google for android.

In android, there are two types of tests we can write:
1. Unit test — It can be achieved by the JUnit framework.
2. Instrumentation test or android test — Espresso comes under this type there are other frameworks like Appium, Robolectric.

Note: Espresso requires an Android emulator or an Android device connected via USB. Add the below dependencies shown below, you also need Junit.

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.espresso"
minSdkVersion 26
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.core:core-ktx:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
implementation group: 'io.mockk', name: 'mockk', version: '1.9.3'
}

So first we will set up the test class:

@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@get:Rule
var mActivityTestRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java)
}

You all noticed there were annotations, ‘@Runwith’ it will tell the Junit to run the test with Android JUnit, @get:Rule in kotlin @Rule in java is the test rules provided by JUnit and it is used launch activity’s.

Before writing tests, we will see the basics of the code of espresso looks,

Basically, espresso contains three parts,
1. View matchers — it is to find view components using withId, withText, etc..
2. View actions — it is used to perform actions like click, longClick, typeText used to enter the value in edit view, etc….
3. View assertions — used to assert like matches and inside it, we can assert isDisplayed, isClickable, etc….

The overall format of the code will be:

onView(View matchers).check(View assertions)
onView(View matchers).check(View assertions).perform(View actions)
  1. Our first test is to check a certain text view is displayed in the main activity:

Add a text view with any text in the activity XML file, I am considering it as welcome text

Now we are going to check a text is displayed in the activity, we can do it by directly entering the text using withText or if it has the id you can also use that,

@Test
fun checkWhetherWelcomeTextIsDisplayed() {
//check text is displayed which has id
onView(withId(R.id.welcome_text)).check(matches(isDisplayed()))
//check text is displayed which does not had an id
onView(withText("Welcome To Espresso World")).
check(matches(isDisplayed()))
}

2. Next, we will automate a button click and check a text is displayed

For this, we will add a button and text view in the main activity and set up ids for it, I am referring as show_text_button, show_text

val showButton = findViewById<Button>(R.id.show_text_button)
showButton.setOnClickListener {
val textView = findViewById<TextView>(R.id.show_text)
textView.text = "Button Clicked"
}

The test will be,

@Test
fun checkButtonIsClickedAndTextIsDisplayed() {
//check text is not displayed
onView(withText("Button Clicked")).check(doesNotExist())
//click button
onView(withId(R.id.show_text_button)).perform(click())
//or if button has no id we can use this
onView(withText("ShowText")).check(matches(isDisplayed())).
perform(click())
//check text is displayed
onView(withText("Button Clicked")).check(matches(isDisplayed()))
}

3. The next test will be typing text edit text field and passing to the next activity with the help of intent by pressing a button,

For that, we will also create a second activity and we will use intent’s getExtra() in second activity and putExtra() in the main activity, like

In the main activity

val details = findViewById<EditText>(R.id.next_activity_edit_text)
val nextActivityButton = findViewById<Button>(R.id.next_activity_button)
nextActivityButton.setOnClickListener {
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("details", details.text.toString())
startActivity(intent)
}

In the second activity

val intent = intent
val welcomeTextDetails = intent.getStringExtra("details")
val welcomeText = findViewById<TextView>(R.id.welcome_text_second_activity)
if (welcomeTextDetails != null)
welcomeText.text = welcomeTextDetails

The test will be like

@Test
fun checkNextActivityButtonGoesToNextActivityWithEnteredText() {
//to type the text in edit text field
onView(withId(R.id.next_activity_edit_text)).
perform(typeText("Welcome SomeOne"),closeSoftKeyboard())
//click next activity button
onView(withId(R.id.next_activity_button)).perform(click())
//check next activity is displayed
onView(withText("WelcomeSomeOne")).check(matches(isDisplayed()))
}

In the first line, we are typing the text in the edit text field with its id and we are closing the keyboard since after typing it will not automatically close and then we are clicking the button and then checking it is displayed in next activity.

4. Our next test depends on how to stub the intent values like putExtra(), for this we will take the second activity which displays text based on getExtra(). So we set up the instrumentation test class for second activity,

@RunWith(AndroidJUnit4::class)
class SecondActivityInstrumentationTest {
@get:Rule
var secondActivityTestRule: ActivityTestRule<SecondActivity> = ActivityTestRule(SecondActivity::class.java,false,false)
}

So if you noticed there is the difference between the main activity and second activity test rule, i.e added two extra boolean values. First one is for intialTouchMode and other is for launchActivity. By changing these boolean values it will not launch activity and we can launch activity in test functions for different intent’s, we can understand by writing the test

@Test
fun shouldCheckTextIsDisplayedPassedThroughIntent() {
val intent = Intent()
intent.putExtra("details", "Hello EveryOne")
secondActivityTestRule.launchActivity(intent)
onView(withText("Hello EveryOne")).check(matches(isDisplayed()))
}

From the above test if you noticed we are launching activity in the test. So we can test with different data for different functionalities.

So I will also attach my GitLab repository link you can also refer this by downloading or cloning:

--

--

Sri Vishnu S
android-core

Developer at ThoughtWorks / Data Science Enthusiast