読者です 読者をやめる 読者になる 読者になる

vaguely

和歌山に戻りました。ふらふらと色々なものに手を出す毎日。

【Android】Espressoを一杯(和歌山トイレマップで遊んでみる 9)

Android SoftwareTesting

はじめに

今回はUIテストツールである、Espressoを使ってみた時のあれこれをまとめます。

インストール

まずはインストールから。EspressoはJUnit4を使用するため、build.gradleに追加します。

build.gradle

~省略~

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "jp.searchwakayamatoilet"
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 2
        versionName "1.1"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    ~省略~
}
~省略~

dependencies {
~省略~
    // App's dependencies, including test
    androidTestCompile 'com.android.support:support-annotations:23.2.0'
    androidTestCompile 'com.android.support.test:runner:0.4.1'
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
~省略~
}
  • 特にdependenciesの記述は結構バージョンごとに違っているようで、見るサンプルごとに異なっていたりもしますが、私の2016.03.08現在の環境では上記の記述以外ではエラーとなるようでした。

テストケースを書く

MainActivityTest.java

~省略~
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.action.ViewActions;
import android.support.test.espresso.matcher.ViewMatchers;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
import android.widget.EditText;
import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;

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

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withText;

@RunWith(AndroidJUnit4.class)
@LargeTest
public class MainActivityViewTest {

    @Rule
    public ActivityTestRule mainActivityRule = new ActivityTestRule(MainActivity.class);

    @Before
    public void setUp() throws Exception {
        // テスト対象ページへの遷移など、テスト前に実行する処理を書く.
    }
    @Test
    public void hasToolbar() throws Exception{
        // Toolbarが表示されているかをチェックする.
        onView(ViewMatchers.withId(R.id.toolbar)).check(matches(isDisplayed()));
    }
~省略~
    @Test
    public void hasEditTextOnSearchView() throws Exception{
        // SearchViewをクリックする.
        onView(ViewMatchers.withId(R.id.searchview)).perform(ViewActions.click());
        // SearchViewの入力欄に「test」と入力してSubmitボタンを押す.
        onView(ViewMatchers.isAssignableFrom(EditText.class)).perform(ViewActions.typeText("test"), ViewActions.pressKey(66));
    }
    @Test
    public void isSuggestSearchAllShown() throws Exception{
        onView(ViewMatchers.withId(R.id.searchview)).perform(ViewActions.click());
        // SearchViewの入力欄に「" "」と入力したあと、「""」に置き換える.
        onView(ViewMatchers.isAssignableFrom(EditText.class)).perform(ViewActions.typeText(" "), ViewActions.replaceText(""));
        // 全件検索用のサジェストが表示されることを確認する.
        onView(ViewMatchers.withId(R.id.suggest_list)).check(matches(isDisplayed()));
    }
    @Test
    public void hasAboutAppButtonInMenu() throws Exception {
        // ToolbarのMenuを表示する.
        openActionBarOverflowOrOptionsMenu(InstrumentationRegistry.getTargetContext());
        // ToolbarのMenuにある「about」ボタンを押す.
        onView(ViewMatchers.withText(R.string.action_about)).perform(ViewActions.click());
    }
    @Test
    public void isAboutFragmentShown() throws Exception {
        // 同じ処理なら別メソッドを呼び出してその後の処理だけを記述することもできる.
        this.hasAboutAppButtonInMenu();
        onView(ViewMatchers.withId(R.id.about_fragment)).check(matches(isDisplayed()));
    }
~省略~
    @Test
    public void hasCreaditsRetrolambdaViewOnAboutAppFragment() throws Exception{
        this.hasAboutAppButtonInMenu();
        // Menuからaboutページを開き、TextViewをスクロール.
        onView(ViewMatchers.withText(R.string.about_credits_retrolambda)).perform(ViewActions.scrollTo(), ViewActions.click());
        onView(ViewMatchers.withId(R.id.about_credits_title_retrolambda)).check(matches(isDisplayed()));
        onView(ViewMatchers.withId(R.id.about_credits_retrolambda)).check(matches(isDisplayed()));
        onView(ViewMatchers.withId(R.id.about_credits_retrolambda_link)).check(matches(isDisplayed()));
    }
~省略~
  • JUnit4を使用するため、@RunWith(AndroidJUnit4.class)をクラスに付与します。
  • 各テストケースには@Testを付与します。
  • 各テストケースの実行順は保証されません。
  • 「matches(isDisplayed())」は画面上に見えている範囲のみチェックするため、ソース上画面内にあったとしても隠れている状態ならテストに失敗します。

終わりに

今回はUIのテストのみを行いました。Mockitoを使った内部処理のテストも取り入れていきたいところです。

参考