An Espresso is a good and fast test automation framework, which allows you test many things inside your application in simple way.
A UiAutomator is perfect framework for automation testing outside of application because this framework allows test many system stuff, as example notification, access to any application, etc.
Fortunately, we can combine these two frameworks in a test. First of all, we start from configuration an Android project. We need to update build.gradle
file in your application module for it.
apply plugin: 'com.android.application'
android {
...
defaultConfig {
...
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
dependencies {
...
//Espresso dependencies
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2') {
exclude group: 'com.android.support', module: 'support-annotations'
}
androidTestCompile('com.android.support.test:runner:0.5') {
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'
}
androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.2') {
exclude group: 'com.android.support', module: 'appcompat'
exclude group: 'com.android.support', module: 'support-v4'
exclude group: 'com.android.support', module: 'support-annotations'
exclude module: 'recyclerview-v7'
}
//UIAutomator dependency
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
}
Note: We need to exclude modules and groups for avoiding version conflict.
I would like to show a small test which use the Espresso and the UiAutomator framework.
@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = 18)
public class CoffeeOrderDetailsActivityTest {
private final static int ORDER_COFFEE_COUNT = 1;
private final static int ESPRESSO_POSITION = 2;
private final static Coffee ESPRESSO = CoffeeService.getCoffeeData().get(ESPRESSO_POSITION);
private final static float TOTAL_PRICE = ESPRESSO.getPrice() * ORDER_COFFEE_COUNT;
private final static String NOTIFICATION_TITLE = "Coffee order app";
private final static String NOTIFICATION_TEXT = "Thank you for your payment.";
private final static String DELIVERY_INFO = "Alex";
private final static int TIMEOUT = 3000;
@Rule
public ActivityTestRule<CoffeeOrderDetailsActivity> mActivityRule =
new ActivityTestRule<>(CoffeeOrderDetailsActivity.class, true, false);
@Test
public void shouldOrderCoffeeAndVerifyNotification() {
String deliveryInfo = null;
TreeMap<Coffee, Integer>; coffeeOrderMap = new TreeMap<>();
coffeeOrderMap.put(ESPRESSO, ORDER_COFFEE_COUNT);
Context context = InstrumentationRegistry.getTargetContext();
Intent intent = CoffeeOrderDetailsActivity.createIntent(context, coffeeOrderMap, deliveryInfo);
mActivityRule.launchActivity(intent);
onView(withId(R.id.total_price_toolbar))
.check(matches(withText(context.getString(R.string.price, TOTAL_PRICE))));
onView(withId(R.id.delivery_info))
.perform(typeText(DELIVERY_INFO), closeSoftKeyboard());
verifyCoffeeOrder();
onView(withId(R.id.pay))
.perform(click());
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
device.openNotification();
device.wait(Until.hasObject(By.text(NOTIFICATION_TITLE)), TIMEOUT);
UiObject2 title = device.findObject(By.text(NOTIFICATION_TITLE));
UiObject2 text = device.findObject(By.text(NOTIFICATION_TEXT));
assertEquals(NOTIFICATION_TITLE, title.getText());
assertEquals(NOTIFICATION_TEXT, text.getText());
title.click();
device.wait(Until.hasObject(By.text(ESPRESSO.getName())), TIMEOUT);
onView(withId(R.id.delivery_info))
.check(matches(withText(mActivityRule.getActivity().getString(R.string.deliver_to_username, DELIVERY_INFO))));
verifyCoffeeOrder();
}
private void verifyCoffeeOrder() {
onData(anything())
.atPosition(0)
.onChildView(withId(R.id.coffee_name)).check(matches(withText(ESPRESSO.getName())));
onData(anything())
.atPosition(0)
.onChildView(withId(R.id.coffee_count))
.check(matches(withText(String.valueOf(ORDER_COFFEE_COUNT))));
}
}
Note: I use an onData
method which works with ListView in this source code. Of course RecyclerView is better than ListView. I used ListView because this example from my small project about testing of Android application, this project contains example of testing RecyclerView and ListView. The whole project you can find here. This project contains different branches.
Finally, few words about an example.
As you probably know, the Espresso much better than UI Automator for testing stuff inside the application. However, UI Automater is better for testing Android stuff outside an application, I mean notification, press buttons, working with any applications, etc.
This part of code is UI Automator part.
UiDevice device = UiDevice.getInstance(
InstrumentationRegistry.getInstrumentation()
);
device.openNotification();
device.wait(Until.hasObject(By.text(NOTIFICATION_TITLE)), TIMEOUT);
UiObject2 title = device.findObject(By.text(NOTIFICATION_TITLE));
UiObject2 text = device.findObject(By.text(NOTIFICATION_TEXT));
assertEquals(NOTIFICATION_TITLE, title.getText());
assertEquals(NOTIFICATION_TEXT, text.getText());
title.click();
device.wait(Until.hasObject(By.text(ESPRESSO.getName())), TIMEOUT);
Here we open notification and verify title and subtitle of notification. Finally, we click on notification and wait application window. Other source code is Espresso part. All espresso code verify stuff inside application.
If you have any question, let me know.
Thank you for your time.
Have a nice day,