Mobile development

Alex Zhukovich

Android testing: Espresso & UIAutomator together

An Espresso is really 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.

A little bit more about Espresso and UI Automator you can read in my previous tutorials.

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.

This short video demonstrates this test from emulator screen.

And finally few words about an example.

As you probably know Espresso is 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 🙂

Share Share on Reddit0Share on VKTweet about this on TwitterShare on LinkedIn5Share on Google+3Share on Facebook5Flattr the authorEmail this to someoneShare on Tumblr0
« »

© 2017 Mobile development. Theme by Anders Norén.