Android Testing

Android testing: Espresso & UIAutomator together

Alex Zhukovich 3 min read
Android testing: Espresso & UIAutomator together
Table of Contents

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,


Mobile development with Alex

A blog about Android development & testing, Best Practices, Tips and Tricks

Share
More from Mobile development with Alex
Not all UI tests are the same
Android Testing

Not all UI tests are the same

The article explores different types of UI testing, such as end-to-end testing, UI testing with fake data, pixel perfection testing, and accessibility testing. The article also includes information on how to get started with UI testing in any project.
Alex Zhukovich 8 min read
How to test Android App Shortcuts
Android Testing

How to test Android App Shortcuts

The "App Shortcuts" feature allows users to access a specific part of the application from the device's home screen. Users can see all available shortcuts by long pressing on the icon of the applications. In this article, we will learn how to test app shortcuts in Android apps.
Alex Zhukovich 5 min read
How to group Android tests
Android Testing

How to group Android tests

Nowadays, mobile apps have many screens so that the projects can have many UI tests. When a project is large, we can have hundreds or thousands of UI tests, and running them locally can be time-consuming. In this article, we will explore different ways of grouping test cases.
Alex Zhukovich 17 min read

Great! You’ve successfully signed up.

Welcome back! You've successfully signed in.

You've successfully subscribed to Mobile development with Alex.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.