Espresso の基本

このドキュメントでは、 Espresso API

Espresso API を使用すると、テスト作成者はユーザーが何をするかという観点で アプリの操作中に行う操作(UI 要素の位置付け、操作) できます。同時に、フレームワークはアクティビティに直接アクセスすることを防止します。 アプリケーションのビューを 1 つずつ保持して、 メインスレッドが UI スレッドから外れていることがテストの不安定性の主な原因となります。したがって、 Espresso API に getView()getCurrentActivity() などのメソッドが表示されない この場合でも、独自のサブクラスを実装することで、ビューを安全に操作できます。 ViewActionViewAssertion

API コンポーネント

Espresso の主なコンポーネントは次のとおりです。

  • Espresso – ビューを操作するためのエントリ ポイント(onView() および onData() など)。ビューに必ずしも関連付けられているとは限らない API( pressBack() として。
  • ViewMatchersMatcher<? 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!" のビューが たとえば、ビューの表示フラグの変更後、 問題ありません。

ビュー アサーションの簡単なテスト

この例では、SimpleActivityButtonTextView が含まれています。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 アドレスを使用して相互に通信できます

警告: AdapterViewonData() で問題が発生する可能性があります メソッドをオーバーライドして、継承契約(特に 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() の オペレーションで NoMatchingViewExceptionAdapterView ウィジェットがスローされ、 ビュー階層内に存在していない場合、最も一般的な解決策は onData() を使用することです。 例外メッセージには、アダプターのビューのリストを示す警告が含まれます。 この情報を使用して、onData() を呼び出し、目的のビューを読み込みます。

参考情報

Android テストでの Espresso の使用について詳しくは、 ご覧ください

サンプル