Hello Folks, This is my second article on Android Instrumentation testing. My previous instrumentation testing article was about testing a list view with core instrumentation (without any external library or framework). In this I am going to discuss the Espresso framework which I use for android instrumentation testing. I have also recored a series of videos on instrumentation testing in Android.
What is Espresso?
Espresso is a framework used for Android Instrumentation Testing. It provides a lots of useful APIs to test the UI elements and simulate the user interaction on the application. Espresso takes care of waiting for the main thread to be idle and perform the actions at the appropriate time. With this we will not have to put hacks like Thread.sleep
in the code. Espresso can run on devices with Android 2.2
or higher (API 8 or higher).
Espresso Matchers
Espresso has two core APIs
- To access the view elements or verify the view elements.
- To perform an action on the view.
For Example below code verifies that element is present on the view
onView(withId(R.id.items_list)).check(matches(isDisplayed()))
onView(withId(R.id.items_list)).check(matches(withChild(withText("Item 1"))))
Below is an example of swiping up the screen and clicking an item on the view
onView(withId(R.id.parent_layout)).perform(swipeUp());
onView(withId(R.id.submit_button)).perform(click());
Setup Espresso
Below is the build config of my demo project
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "ajitsingh.com.instrumentationtestdemo"
minSdkVersion 21
targetSdkVersion 22
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'LICENSE.txt'
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:support-annotations:22.2.0'
androidTestCompile 'com.android.support.test:rules:0.3'
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2') {
exclude group: 'com.android.support', module: 'support-annotations'
}
androidTestCompile('com.android.support.test.espresso:espresso-intents:2.2') {
exclude group: 'com.android.support', module: 'support-annotations'
}
}
Example
I have created a demo project which has one test class which uses espresso and another with core instrumentation
@RunWith(AndroidJUnit4.class)
public class ItemListActivityEspressoTest {
@Rule
public ActivityTestRule<ItemListActivity> main = new ActivityTestRule<ItemListActivity>(ItemListActivity.class){
@Override
protected void beforeActivityLaunched() {
Intents.init();
super.beforeActivityLaunched();
}
@Override
protected void afterActivityFinished() {
super.afterActivityFinished();
Intents.release();
}
};
@Test
public void shouldLaunchTheMainActivityAndFindItemsInTheList() throws Exception {
onView(withId(R.id.items_list)).check(matches(withChild(withText("Item 1"))));
onView(withId(R.id.items_list)).check(matches(withChild(withText("Item 2"))));
onView(withId(R.id.items_list)).check(matches(withChild(withText("Item 3"))));
onView(withId(R.id.items_list)).check(matches(withChild(withText("Item 4"))));
}
@Test
public void shouldShowTheItemDetailWhenAnItemIsClicked() throws Exception {
intending(hasComponent(ItemDetailActivity.class.getName()))
.respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, new Intent()));
onView(withText("Item 1")).perform(click());
intended(hasComponent(ItemDetailActivity.class.getName()));
}
}