このドキュメントでは、 Espresso API
Espresso API を使用すると、テスト作成者はユーザーが何をするかという観点で
アプリの操作中に行う操作(UI 要素の位置付け、操作)
できます。同時に、フレームワークはアクティビティに直接アクセスすることを防止します。
アプリケーションのビューを 1 つずつ保持して、
メインスレッドが UI スレッドから外れていることがテストの不安定性の主な原因となります。したがって、
Espresso API に getView()
や getCurrentActivity()
などのメソッドが表示されない
この場合でも、独自のサブクラスを実装することで、ビューを安全に操作できます。
ViewAction
と ViewAssertion
。
API コンポーネント
Espresso の主なコンポーネントは次のとおりです。
- Espresso – ビューを操作するためのエントリ ポイント(
onView()
およびonData()
など)。ビューに必ずしも関連付けられているとは限らない API(pressBack()
として。 - ViewMatchers –
Matcher<? super View>
インターフェース。これらのうちの 1 つ以上をonView()
メソッドを使用して、現在のビュー階層内でビューを検索します。 - ViewActions - 渡すことのできる
ViewAction
オブジェクトのコレクションViewInteraction.perform()
メソッド(click()
など)。 - ViewAssertions - 表示可能な
ViewAssertion
オブジェクトのコレクションViewInteraction.check()
メソッドが渡されていることを示します。ほとんどの場合、 アサーションに一致します。このアサーションでは、View マッチャーを使用して、 表示されます。
例:
Kotlin
// withId(R.id.my_view) is a ViewMatcher // click() is a ViewAction // matches(isDisplayed()) is a ViewAssertion onView(withId(R.id.my_view)) .perform(click()) .check(matches(isDisplayed()))
Java
// withId(R.id.my_view) is a ViewMatcher // click() is a ViewAction // matches(isDisplayed()) is a ViewAssertion onView(withId(R.id.my_view)) .perform(click()) .check(matches(isDisplayed()));
ビューの特定
ほとんどの場合、onView()
メソッドは Hamcrest マッチャーを使用します。
(現在のビュー内の 1 つのビューにのみ一致します)
継承されます。Matcher は強力であり、
実装する必要がありますHamcrest マッチャーに詳しくない方は、
まずは、こちらの
プレゼンテーションをご覧ください。
多くの場合、目的のビューには一意の R.id
があり、単純な withId
マッチャーを使用すると
ビュー検索を絞り込むことができますただし、正当な理由も数多くあり、
テスト開発時に R.id
を特定できない。たとえば特定のビューは
R.id
がないか、R.id
が一意でない。これは通常
インストルメンテーション テストが脆弱で複雑な場合です。これは、通常の実行方法は、
findViewById()
を使用してビューにアクセスしようとしても機能しません。そのため
ビューまたはフラグメントを保持する Activity または Fragment のプライベート メンバーにアクセスする必要がある
既知の R.id
を持つコンテナを見つけて、そのコンテンツに移動し、
表示されます。
Espresso ではビューを絞り込むことで、この問題をスムーズに解決できます。
既存の ViewMatcher
オブジェクトまたは独自のカスタム オブジェクトを使用します。
R.id
によるビューの特定は、onView()
を呼び出すことで簡単に行えます。
Kotlin
onView(withId(R.id.my_view))
Java
onView(withId(R.id.my_view));
複数のビューが同じ R.id
値を持つ場合があります。この場合
特定の R.id
を使用しようとすると、次のような例外が発生します。
AmbiguousViewMatcherException
。例外メッセージでは、次のメッセージが表示されます。
の 2 つのビューがあります。このビュー階層を検索して、
一意でない R.id
に一致するビュー:
java.lang.RuntimeException: androidx.test.espresso.AmbiguousViewMatcherException This matcher matches multiple views in the hierarchy: (withId: is <123456789>) ... +----->SomeView{id=123456789, res-name=plus_one_standard_ann_button, visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true, window-focus=true, is-focused=false, is-focusable=false, enabled=true, selected=false, is-layout-requested=false, text=, root-is-layout-requested=false, x=0.0, y=625.0, child-count=1} ****MATCHES**** | +------>OtherView{id=123456789, res-name=plus_one_standard_ann_button, visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true, window-focus=true, is-focused=false, is-focusable=true, enabled=true, selected=false, is-layout-requested=false, text=Hello!, root-is-layout-requested=false, x=0.0, y=0.0, child-count=1} ****MATCHES****
ビューのさまざまな属性を調べると、
できます。上記の例では、ビューの 1 つに
"Hello!"
。次の条件を組み合わせて検索を絞り込むことができます。
matcher:
Kotlin
onView(allOf(withId(R.id.my_view), withText("Hello!")))
Java
onView(allOf(withId(R.id.my_view), withText("Hello!")));
どのマッチャーも、not 関数を使用することで、値を反転させることができます。
Kotlin
onView(allOf(withId(R.id.my_view), not(withText("Unwanted"))))
Java
onView(allOf(withId(R.id.my_view), not(withText("Unwanted"))));
ViewMatchers
を参照してください。
Espresso のビュー マッチャーについて説明します。
考慮事項
- 正常に動作するアプリケーションでは、ユーザーが操作できるすべてのビュー
説明テキストを含めるか、コンテンツの説明を含めます。詳しくは、
アプリのユーザー補助機能を強化する
表示されます。
withText()
を使用して検索を絞り込めない場合、またはwithContentDescription()
は、ユーザー補助のバグとして扱います。 - 目的のビューを見つけるマッチャーは最小限にする
できます。過度に指定すると、フレームワークに
必要です。たとえば、ビューをテキストで一意に識別できる場合は、
ビューが
TextView
からも割り当て可能であることを指定する必要はありません。多くの人にとって ビューのR.id
で十分です。 - ターゲット ビューが
AdapterView
内にある場合(ListView
など)、GridView
またはSpinner
-onView()
メソッドが機能しない場合があります。対象 代わりにonData()
を使用してください。
ビューでのアクションの実行
ターゲット ビューに適したマッチャーが見つかったら、
process メソッドを使用して、そのインスタンスに対して ViewAction
のインスタンスを実行します。
たとえば、次のようにしてそのビューをクリックします。
Kotlin
onView(...).perform(click())
Java
onView(...).perform(click());
次のように、1 回の perform 呼び出しで複数のアクションを実施できます。
Kotlin
onView(...).perform(typeText("Hello"), click())
Java
onView(...).perform(typeText("Hello"), click());
作業中のビューが ScrollView
(垂直または
先行するアクションでは、ビューを水平方向に
(click()
、typeText()
など)を scrollTo()
で表示できます。この
他のアクションに進む前に、必ずビューが表示されているようにします。
Kotlin
onView(...).perform(scrollTo(), click())
Java
onView(...).perform(scrollTo(), click());
ViewActions
を参照してください。
Espresso の機能をご覧ください。
ビュー アサーションの確認
check()
を使用すると、現在選択されているビューにアサーションを適用できます。
メソッドを呼び出します。よく使用されるアサーションは matches()
です。使用される
ViewMatcher
オブジェクトを使用して、現在選択されているビューの状態をアサートします。
たとえば、ビューにテキスト "Hello!"
が含まれることを確認するには、次のようにします。
Kotlin
onView(...).check(matches(withText("Hello!")))
Java
onView(...).check(matches(withText("Hello!")));
ビューのコンテンツに "Hello!"
が含まれているかどうかをアサーションする場合の不適切な例を次に示します。
Kotlin
// Don't use assertions like withText inside onView. onView(allOf(withId(...), withText("Hello!"))).check(matches(isDisplayed()))
Java
// Don't use assertions like withText inside onView. onView(allOf(withId(...), withText("Hello!"))).check(matches(isDisplayed()));
一方、テキスト "Hello!"
のビューが
たとえば、ビューの表示フラグの変更後、
問題ありません。
ビュー アサーションの簡単なテスト
この例では、SimpleActivity
に Button
と TextView
が含まれています。Google
ボタンをクリックすると、TextView
の内容が "Hello Espresso!"
に変わります。
Espresso では、これを次のようにテストします。
ボタンのクリック
最初のステップとして、ボタンの特定に役立つプロパティを探します。「
想定どおり、SimpleActivity
のボタンには一意の R.id
があります。
Kotlin
onView(withId(R.id.button_simple))
Java
onView(withId(R.id.button_simple));
次のようにすると、クリックが行えます。
Kotlin
onView(withId(R.id.button_simple)).perform(click())
Java
onView(withId(R.id.button_simple)).perform(click());
TextView のテキストの確認
確認対象のテキストを含む TextView
にも一意の R.id
があります。
Kotlin
onView(withId(R.id.text_simple))
Java
onView(withId(R.id.text_simple));
次のようにすると、コンテンツのテキストが確認できます。
Kotlin
onView(withId(R.id.text_simple)).check(matches(withText("Hello Espresso!")))
Java
onView(withId(R.id.text_simple)).check(matches(withText("Hello Espresso!")));
アダプター ビューでのデータ読み込みの確認
AdapterView
は、データを動的に読み込む特別なタイプのウィジェットです。
アダプタです。AdapterView
の最も一般的な例は ListView
です。として
LinearLayout
のような静的なウィジェットとは対照的に、
AdapterView
個の子を現在のビュー階層に読み込めます。シンプル
onView()
検索で、現在読み込まれていないビューは検出されません。
Espresso では、これに対処するために、個別の onData()
エントリ ポイントを提供しています。
まず問題のアダプター項目を読み込んでから
その項目に焦点を合わせることができます
内部 IP アドレスを使用して相互に通信できます
警告:
AdapterView
は onData()
で問題が発生する可能性があります
メソッドをオーバーライドして、継承契約(特に
getItem()
API。そのような場合の最善の策は、
リファクタリングする必要がありますそれができない場合は、
一致するカスタム AdapterViewProtocol
。詳細については、
デフォルトの
<ph type="x-smartling-placeholder"></ph>
Espresso が提供する AdapterViewProtocols
クラス。
アダプター ビューの簡単なテスト
ここでは、簡単なテストを通じて onData()
の使用方法を説明します。SimpleActivity
には以下が含まれる:
コーヒー飲料の種類を表すいくつかのアイテムを持つ Spinner
。特定の
アイテムが選択されると、"One %s a day!"
に変わる TextView
があります。
%s
は、選択された項目を表します。
このテストの目標は、Spinner
を開いて特定のアイテムを選択し、
TextView
にアイテムが含まれていることを確認します。Spinner
クラスは、
の AdapterView
では、次の期間に onView()
ではなく onData()
を使用することをおすすめします。
照合されます。
項目の選択を開く
Kotlin
onView(withId(R.id.spinner_simple)).perform(click())
Java
onView(withId(R.id.spinner_simple)).perform(click());
アイテムを選択
アイテムを選択するために、Spinner
はその内容を含む ListView
を作成します。
このビューは非常に長くなる可能性があり、要素がビューに貢献していない可能性があります。
継承されます。onData()
を使用して、目的の要素をビューに強制的に挿入します。
継承されます。Spinner
内のアイテムは文字列であるため、マッチングの対象にしたいのは
"Americano"
:
Kotlin
onData(allOf(`is`(instanceOf(String::class.java)), `is`("Americano"))).perform(click())
Java
onData(allOf(is(instanceOf(String.class)), is("Americano"))).perform(click());
テキストが正しいことの確認
Kotlin
onView(withId(R.id.spinnertext_simple)) .check(matches(withText(containsString("Americano"))))
Java
onView(withId(R.id.spinnertext_simple)) .check(matches(withText(containsString("Americano"))));
デバッグ
テストが失敗した場合、Espresso からデバッグに役立つ情報を入手できます。
ログ
Espresso では、すべてのビュー アクションが logcat に記録されます。例:
ViewInteraction: Performing 'single click' action on view with text: Espresso
ビュー階層
onView()
の場合に Espresso が例外メッセージにビュー階層を出力する
失敗します
onView()
でターゲット ビューが見つからなかった場合、NoMatchingViewException
が返されます。 発生します。例外文字列のビュー階層を調べて、分析できる マッチャーがどのビューとも一致しない理由onView()
で、指定したマッチャーに一致するビューが複数見つかった場合は、AmbiguousViewMatcherException
がスローされます。ビュー階層が出力されます。 一致したビューにはMATCHES
ラベルが付きます。
java.lang.RuntimeException: androidx.test.espresso.AmbiguousViewMatcherException This matcher matches multiple views in the hierarchy: (withId: is <123456789>) ... +----->SomeView{id=123456789, res-name=plus_one_standard_ann_button, visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true, window-focus=true, is-focused=false, is-focusable=false, enabled=true, selected=false, is-layout-requested=false, text=, root-is-layout-requested=false, x=0.0, y=625.0, child-count=1} ****MATCHES**** | +------>OtherView{id=123456789, res-name=plus_one_standard_ann_button, visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true, window-focus=true, is-focused=false, is-focusable=true, enabled=true, selected=false, is-layout-requested=false, text=Hello!, root-is-layout-requested=false, x=0.0, y=0.0, child-count=1} ****MATCHES****
複雑なビュー階層やウィジェットの予期しない動作に対処する場合 常に使用ルールを Android Studio の Hierarchy Viewer 説明します。
アダプター ビューの警告
Espresso では、AdapterView
ウィジェットの存在に関する警告がユーザーに表示されます。onView()
の
オペレーションで NoMatchingViewException
と AdapterView
ウィジェットがスローされ、
ビュー階層内に存在していない場合、最も一般的な解決策は onData()
を使用することです。
例外メッセージには、アダプターのビューのリストを示す警告が含まれます。
この情報を使用して、onData()
を呼び出し、目的のビューを読み込みます。
参考情報
Android テストでの Espresso の使用について詳しくは、 ご覧ください
サンプル
- CustomMatcherSample:
EditText
オブジェクトの hint プロパティに対応するように Espresso を拡張する方法を示します。 - RecyclerViewSample:
Espresso の
RecyclerView
アクション。 - (その他)