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

うさがにっき

読書感想文とプログラムのこと書いてきます

Espressoの基本的な使い方

概要

Espressoを使った自動化テスト環境を作成する - うさがにっき
の続き
Espressoの主なコンポーネントを理解し、基本的な使い方をまとめる

詳細

基本的な構成要素

  • Espresso

Viewとのインタラクションのエントリーポイント(onView, onDataなど)
pressBackのようなViewに紐付かないものも扱う

  • ViewMatchers

Matcherの実装を集めたもの
それらは現在のViewの構造から目的のViewが何処にあるのかを特定するためにonViewメソッドなどに渡すことができる

  • ViewActions

クリックやスクロールといったアクションを表すものを集めたもの
それらはViewInteraction.performメソッドに渡せる

  • ViewAssertions

ViewAssertionsを集めたもので、ViewInteraction.checkメソッドに渡すことができる
ほとんどの場合は選択中のViewの状態を確認するのにmatchassertionを使う

        onView(withText("Hello World!")) // ViewMatcher
                .perform(click()) // ViewAction
                .check(matches(isDisplayed())); // ViewAssertion

onViewメソッドを使ってViewを探す方法

ほとんどの場合、onViewメソッドは対象となるViewを1つに絞り込めるMatcherを使う
多くの場合、目的となるR.idでユニークになるIDを持ち、シンプルにwithIdメソッドで検索することができる
しかし、開発中ではR.idで特定できないケースがよくある、例えばR.idを持たない場合や、R.idが複数のViewでユニークでない場合
この場合R.idによるアクセスは役に立たないため、VieweMatchersやカスタムされたViewMatchersを使うことでViewを明確に絞り込むことができる

R.idでViewを見つけ出すのはシンプルに以下のようにする

        onView(withId(R.id.hello_world));

前述の通り、R.idは複数のViewでユニークでない時がある
このような場合以下のような例外が投げられる

android.support.test.espresso.AmbiguousViewMatcherException: 'with id: suumotools.android.recruit.co.jp.espressotest:id/hello_world' matches multiple views in the hierarchy.
Problem views are marked with '****MATCHES****' below.

View Hierarchy:
+>DecorView{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=1}
|
+->LinearLayout{id=-1, visibility=VISIBLE, width=1080, height=1920, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0, child-count=2}
|
+-->ViewStub{id=16909070, visibility=GONE, width=0, height=0, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=true, is-selected=false, root-is-layout-requested=false, has-input-connection=false, x=0.0, y=0.0}

このような場合、id以外にも様々な属性からViewを探すことができる
例えば文字列から探すこともできる

onView(allOf(withId(R.id.hello_world), withText("Hello World!")));

Viewのアクションを実行する

目的のViewを見つけるのにちょうど良いMatacherが見つかれば、ViewのActionを実行することができる

        // onView(<Matcher>).perform(click());
        onView(allOf(withId(R.id.hello_world), withText("Hello World!"))).perform(click());

また、一回のperformメソッド複数のActionを実行することができる

        onView(allOf(withId(R.id.hello_world), withText("Hello World!"))).perform(typeText("Hello"),click());

もしScrollViewの中に配置されたViewを扱う場合、そのViewを表示させてからActionを実行する必要がある
以下のようにすると確実にViewを表示させてからclickを実行できる

        onView(allOf(withId(R.id.hello_world), withText("Hello World!"))).perform(scrollTo(), click());

Viewが条件を満たしているか確認する

Viewが条件を満たしているかはonViewやonDataで選択されたViewにcheckメソッドを使うことで調べることができる
通常使われるのはmatchesアサーションで、選択されているViewの現在どのような状態にあるのか確認するためにViewMatcherが使われる
例えばHello World!という文字列が表示されているか確認したい時は以下のようにする

        onView(withId(R.id.hello_world)).check(matches(withText("Hello World!")));

しかし、チェックしたい内容をonViewメソッドの引数に書くことはよくない
上記を以下のように書いたとする

        onView(allOf(withId(R.id.hello_world), withText("Hello World!"))).check(matches(isDisplayed()));

これではテストに失敗した際、表示されていることが問題なのか、Viewに設定されている文字列が不適切なのかが判断できない
一方、文字列が表示されたViewが表示されていることを確認したい時はこの書き方は正しい
適切な書き方を選ぶべき