Written by Alistair Sykes
Jun 09, 2017

Code snippets in Espresso

A few snippets from Espresso - the automated testing framework for Android

Android Espresso

Here at Brightec we aim to include an extensive range of UI tests with our code. We do this to ensure our code is stable and functioning as expected.

For Android, this comes in the shape of Espresso tests.

The Espresso testing framework gives developers the ‘language’ with which to express their UI test desires.

For the most part, it is reasonably straight forward. However, on rare occasions, or for more obscure UI, it can be difficult to work out the details of the test.

So to help other Android developers, I’ve collated below a (somewhat random) selection of code snippets using Espresso that should be of use to others. Enjoy!

Espresso Snippets

The Espresso framework is extremely powerful but can be quite complex.

Although the Android Studio Test Recorder is improving rapidly, you will still need to tinker your tests manually.

In this post, I am outlining a couple of little snippets of code which I have come across, which might help you in your test writing. These are the ones that I found a bit more tricky or more difficult to find answers to. 

Don’t forget to disable animations on the device you are testing on and be sure to check out the test recorder. It is great for creating a starting point for your test and then you can edit it from there.

Spinners

 

Selecting an item from a spinner is surprisingly easy. It’s simply a case of getting your spinner view (ViewInteraction), performing a click and then leveraging the onData functionality.

ViewInteraction spinner1 = onView(allOf(withId(R.id.spinner_1),
                    withParent(withId(R.id.linear_spinner_parent_1))));
spinner1.perform(scrollTo(), click());
onData(hasToString(stringYouWantToSelect1)).perform(click());

ViewInteraction spinner2 = onView(allOf(withId(R.id.spinner_2),
                    withParent(withId(R.id.linear_spinner_parent_2))));
spinner2.perform(scrollTo(), click());
onData(hasToString(stringYouWantToSelect2)).perform(click());

You can use a few different ways of matching the selection you want but the hasToString is quite a nice one. And as you can see you can select multiple spinners in one test, the onData works out which spinner menu is currently showing.

Starting new Activity

Checking a new activity has started can be a vital part of your testing strategy and can be done by creating an ActivityMonitor and then waitForActivityWithTimeout(). Then all that’s left is to assert that am.getHits() equals the number of times your activity should launch i.e. 1.

Instrumentation.ActivityMonitor am = getInstrumentation().addMonitor(
NextActivity.class.getName(), null, true);
ViewInteraction button = onView(withId(R.id.button_next));
button.perform(scrollTo(), click());
am.waitForActivityWithTimeout(3000);
assertEquals(1, am.getHits());

Why might you need this? I have used this in order to get hold of a view to use in an idling resource.

public static Activity getActivity() {
        final Activity[] currentActivity = new Activity[1];
        onView(allOf(withId(android.R.id.content), isDisplayed())).perform(new ViewAction() {
            @Override
            public Matcher getConstraints() {
                return isAssignableFrom(View.class);
            }

            @Override
            public String getDescription() {
                return "Getting activity";
            }

            @Override
            public void perform(UiController uiController, View view) {
                if (view.getContext() instanceof Activity) {
                    Activity activity1 = ((Activity) view.getContext());
                    currentActivity[0] = activity1;
                }
            }
        });
        return currentActivity[0];
    }

Idling Resources

I have used a couple of different idling resources which are used to effectively wait for something to happen during a test. Hopefully, these will inspire you to write your own. TextViewHasTextIdlingResource.java

public class TextViewHasTextIdlingResource implements IdlingResource {

    private final TextView mView;
    private final boolean mHasText;

    private boolean mIdle;
    private ResourceCallback mResourceCallback;

    public TextViewHasTextIdlingResource(final TextView view, boolean hasText) {
        this.mView = view;
        this.mHasText = hasText;
        this.mIdle = false;
        this.mResourceCallback = null;
    }

    @Override
    public final String getName() {
        return TextViewHasTextIdlingResource.class.getSimpleName();
    }

    @Override
    public final boolean isIdleNow() {
        mIdle = mIdle || (mHasText != Strings.isNullOrEmpty(mView.getText().toString()));

        if (mIdle && mResourceCallback != null) {
            mResourceCallback.onTransitionToIdle();
        }

        return mIdle;
    }

    @Override
    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
        mResourceCallback = resourceCallback;
    }
}

ViewVisibilityIdlingResource.java

public class ViewVisibilityIdlingResource implements IdlingResource {

    private final View mView;
    private final int mExpectedVisibility;

    private boolean mIdle;
    private IdlingResource.ResourceCallback mResourceCallback;

    public ViewVisibilityIdlingResource(final View view, int expectedVisibility) {
        this.mView = view;
        this.mExpectedVisibility = expectedVisibility;
        this.mIdle = false;
        this.mResourceCallback = null;
    }

    @Override
    public final String getName() {
        return ViewVisibilityIdlingResource.class.getSimpleName();
    }

    @Override
    public final boolean isIdleNow() {
        mIdle = mIdle || mView.getVisibility() == mExpectedVisibility;

        if (mIdle && mResourceCallback != null) {
            mResourceCallback.onTransitionToIdle();
        }

        return mIdle;
    }

    @Override
    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
        mResourceCallback = resourceCallback;
    }
}

ViewHasChildrenIdlingResource.java

public class ViewHasChildrenIdlingResource implements IdlingResource {

    private final ViewGroup mView;
    private final int mExpectedNoOfChildren;

    private boolean mIdle;
    private ResourceCallback mResourceCallback;

    public ViewHasChildrenIdlingResource(final ViewGroup view, int noOfChildren) {
        this.mView = view;
        this.mExpectedNoOfChildren = noOfChildren;
        this.mIdle = false;
        this.mResourceCallback = null;
    }

    @Override
    public final String getName() {
        return ViewHasChildrenIdlingResource.class.getSimpleName();
    }

    @Override
    public final boolean isIdleNow() {
        mIdle = mIdle || mView.getChildCount() >= mExpectedNoOfChildren;

        if (mIdle && mResourceCallback != null) {
            mResourceCallback.onTransitionToIdle();
        }

        return mIdle;
    }

    @Override
    public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
        mResourceCallback = resourceCallback;
    }
}

TextView Url

To test clicking on a URL within a text view tries to open that URL you can do the following:

ViewInteraction textView = onView(
                allOf(withId(R.id.text_info),
                        withParent(withId(R.id.relative_main))));
textView.perform(ViewActions.openLinkWithText("terms and conditions"));
intended(allOf(hasAction(Intent.ACTION_VIEW), hasData(Uri.parse("http://www.google.co.uk"))));
Top