May 1, 2017

EspressoでExpandableListViewをクリックして、遷移先が正しいActivityかテストする

メモです。テスト対象のActivityにExpandableListViewがあり、子をクリックすると特定のActivityに遷移する。という想定です。
package my.app.Activity;

import android.app.Activity;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.core.deps.guava.collect.Iterables;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
import android.support.test.runner.lifecycle.Stage;
import android.test.ActivityInstrumentationTestCase2;

import my.app.R;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static android.support.test.espresso.Espresso.*;
import static android.support.test.espresso.matcher.ViewMatchers.*;
import static android.support.test.espresso.action.ViewActions.*;
import static org.hamcrest.Matchers.*;

@RunWith(AndroidJUnit4.class)
public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {
    private MainActivity mActivity;

    public MainActivityTest() {
        super(MainActivity.class);
    }

    @Before
    public void setUp() throws Exception {
        super.setUp();
        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
        mActivity = getActivity();
    }

    @After
    public void tearDown() throws Exception {
        super.tearDown();
    }

    @Test
    public void test_ExpandableListView() throws Throwable {
        // 遷移前のアクティビディを確認する
        assertThat(mActivity, instanceOf(MainActivity.class));

        // 親をクリックする
        String groupText = "TARGET_GROUP_TITLE";
        onView(withText(groupText)).perform(click());

        // 子をクリックする
        String childText = "TARGET_CHILD_TITLE";
        onView(withText(childText)).perform(click());

        // 遷移先のアクティビディを確認する
        assertThat(getCurrentActivity(), instanceOf(TargetActivity.class));
    }

    // @see http://stackoverflow.com/questions/24517291/get-current-activity-in-espresso-android
    private Activity getCurrentActivity() throws Throwable {
        getInstrumentation().waitForIdleSync();
        final Activity[] activity = new Activity[1];

        runTestOnUiThread(new Runnable() {
            @Override
            public void run() {
                java.util.Collection<Activity> activites = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED);
                activity[0] = Iterables.getOnlyElement(activites);
            }
        });

        return activity[0];
    }
}
ついでにEspresso関係で app/build.gradle に追記した箇所もメモ。
android {
    ...
    defaultConfig {
        ...
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
}

dependencies {
    ...
    androidTestCompile 'com.android.support.test:runner:0.3'
    androidTestCompile 'com.android.support.test:rules:0.3'
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2'
}
これで良いのだろうか。