Espresso-Web は、Android WebView UI コンポーネントを操作するためのエントリ ポイントです。広く利用されている WebDriver API から Atom を再利用し、WebView の動作の確認や制御が行えます。
Espresso-Web を使用するケース
Espresso-Web を使用して、ハイブリッド アプリ(特にアプリのネイティブ UI コンポーネントと WebView
UI コンポーネントの統合)をテストします。Espresso-Web API を他の Espresso API と組み合わせて使用することで、WebView
オブジェクト内のウェブ要素を完全に操作できます。
WebView
自体のみをテストする必要があり、WebView
とアプリのネイティブ コンポーネント間のやり取りはテストする必要がない場合は、WebDriver などのフレームワークを使用して一般的なウェブテストを作成することを検討してください。ウェブテスト フレームワークを使用する場合は、Android デバイスや Java 仮想マシンを使用する必要がないため、テストをより迅速かつ確実に実行できます。とはいえ、Espresso-Web ではカスタムの WebDriver Atom を再利用できるため、特にスタンドアロン ウェブアプリと Android UI を含むアプリの両方に対して実行するテストを作成する場合には、高い柔軟性が得られます。
仕組み
Espresso の onData()
メソッドと同様に、WebView
インタラクションは複数の Atom で構成されます。WebView
インタラクションは、Java プログラミング言語と JavaScript ブリッジを組み合わせて処理を行います。JavaScript 環境からデータを公開しても、競合状態が発生する可能性はないため、Espresso が Java ベース側で認識するものはすべて分離されたコピーです。Web.WebInteraction
オブジェクトからのデータの取得は完全にサポートされており、リクエストから返されるすべてのデータを検証できます。
WebDriver Atom とは
WebDriver フレームワークは、Atom を使用して、プログラムでウェブ要素を検出、操作します。WebDriver でのブラウザ操作は Atom を通じて実現しており、Atom は概念的には、UI でアクションを実行する自己完結型ユニットである ViewAction
に似ています。findElement()
や getElement()
などの定義済みメソッドのリストを使用して Atom を公開し、ユーザーの視点からブラウザを操作します。ただし、WebDriver フレームワークを直接使用する場合、Atom を適切にオーケストレートする必要があり、非常に冗長なロジックが必要になります。
Espresso では、Web
クラスと Web.WebInteraction
クラスがこのボイラープレートをラップしており、Espresso のような感覚で WebView オブジェクトを操作できます。したがって、WebView
のコンテキストでは、Atom は従来の Espresso の ViewMatchers
や ViewActions
の代わりに使用されます。
API の表記は、次のように非常にシンプルです。
Kotlin
onWebView() .withElement(Atom) .perform(Atom) .check(WebAssertion)
Java
onWebView() .withElement(Atom) .perform(Atom) .check(WebAssertion);
詳細については、Selenium の Atom に関するドキュメントをご覧ください。
WebView の実装
アプリのテストで WebView
を操作するには、次のセクションのガイダンスに従ってください。
パッケージ
Espresso-Web をプロジェクトに含めるには、次の手順を行います。
- アプリの
build.gradle
ファイルを開きます。これは通常、最上位のbuild.gradle
ファイルではなく、app/build.gradle
です。 依存関係内に次の行を追加します。
Groovy
androidTestImplementation 'androidx.test.espresso:espresso-web:3.4.0'
Kotlin
androidTestImplementation('androidx.test.espresso:espresso-web:3.4.0')
Espresso-Web と互換性があるのは Espresso 2.2 以降およびテスト ライブラリのバージョン 0.3 以降であるため、これらの行も必ず更新してください。
Groovy
androidTestImplementation 'androidx.test:runner:1.4.0' androidTestImplementation 'androidx.test:rules:1.4.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
Kotlin
androidTestImplementation('androidx.test:runner:1.4.0') androidTestImplementation('androidx.test:rules:1.4.0') androidTestImplementation('androidx.test.espresso:espresso-core:3.4.0')
API の一般的な使用方法
onWebView()
メソッドは、Espresso を使用して Android 上で WebView を操作する際のメインのエントリ ポイントです。このメソッドを使用して、次のような Espresso-Web テストを実行します。
Kotlin
onWebView() .withElement(findElement(Locator.ID, "link_2")) // similar to onView(withId(...)) .perform(webClick()) // Similar to perform(click()) // Similar to check(matches(...)) .check(webMatches(getCurrentUrl(), containsString("navigation_2.html")))
Java
onWebView() .withElement(findElement(Locator.ID, "link_2")) // similar to onView(withId(...)) .perform(webClick()) // Similar to perform(click()) // Similar to check(matches(...)) .check(webMatches(getCurrentUrl(), containsString("navigation_2.html")));
この例では、Espresso-Web は ID が "link_2"
の DOM 要素を見つけてクリックします。続いて、WebView が "navigation_2.html"
文字列を含む GET リクエストを送信することを確認します。
JavaScript のサポート
テストの実行時に、システムは JavaScript を使用してすべての WebView インタラクションを実行します。したがって、JavaScript の評価をサポートするには、テスト対象の WebView で JavaScript を有効にする必要があります。
JavaScript を強制的に有効にするには、次のコード スニペットに示すように、テスト対象のアクティビティのアクションとして forceJavascriptEnabled()
を呼び出します。
@RunWith(AndroidJUnit4::class) class MyTestSuite { @get:Rule val activityScenarioRule = activityScenarioRule<MyWebViewActivity>() @Test fun testWebViewInteraction() { onWebView().forceJavascriptEnabled() } }
一般的なウェブ操作
Web.WebInteraction
オブジェクトを使用する一般的な操作には、次のようなものがあります。
-
withElement()
は、WebView 内の DOM 要素を参照します。例:
Kotlin
onWebView().withElement(findElement(Locator.ID, "teacher"))
Java
onWebView().withElement(findElement(Locator.ID, "teacher"));
-
withContextualElement()
は、WebView 内のスコープ設定された DOM 要素を別の DOM 要素から相対的に参照します。最初にwithElement()
を呼び出して、参照Web.WebInteraction
オブジェクト(DOM 要素)を確立する必要があります。例:
Kotlin
.withElement(findElement(Locator.ID, "teacher")) .withContextualElement(findElement(Locator.ID, "person_name"))
Java
.withElement(findElement(Locator.ID, "teacher")) .withContextualElement(findElement(Locator.ID, "person_name"));
-
check()
は条件を評価して、true
に解決されることを確認します。例:
Kotlin
onWebView() .withElement(findElement(Locator.ID, "teacher")) .withContextualElement(findElement(Locator.ID, "person_name")) .check(webMatches(getText(), containsString("Socrates")))
Java
onWebView() .withElement(findElement(Locator.ID, "teacher")) .withContextualElement(findElement(Locator.ID, "person_name")) .check(webMatches(getText(), containsString("Socrates")));
-
perform()
は、要素のクリックなど、WebView 内でアクションを実行します。例:
Kotlin
onWebView() .withElement(findElement(Locator.ID, "teacher")) .perform(webClick())
Java
onWebView() .withElement(findElement(Locator.ID, "teacher")) .perform(webClick());
-
reset()
: WebView を初期状態に戻します。これは、クリックなどの前の操作によってナビゲーションの変更が導入されて ElementReference オブジェクトと WindowReference オブジェクトにアクセスできなくなる場合に必要です。注:
reset()
は、フォーム送信など、複数ページのワークフローに対してアサーションを行う場合に便利です。ただし、通常はテストのスコープを限定し、1 つのページに焦点を当てる必要があります。例:
Kotlin
onWebView() .withElement(...) .perform(...) .reset()
Java
onWebView() .withElement(...) .perform(...) .reset();
例
次の例では、WebView にテキストを入力して [送信] ボタンを選択した後、同じ WebView 内の別の要素内に同じテキストが表示されるかどうかをテストします。
Kotlin
const val MACCHIATO = "Macchiato" @RunWith(AndroidJUnit4::class) class MyEspressoWebTestSuite { @Test fun typeTextInInput_clickButton_SubmitsForm() { // Create an intent that displays a web form. val webFormIntent = Intent() // ... // Lazily launch the Activity with a custom start Intent per test. ActivityScenario.launchActivity(webFormIntent) // Selects the WebView in your layout. If you have multiple WebView // objects, you can also use a matcher to select a given WebView, // onWebView(withId(R.id.web_view)). onWebView() // Find the input element by ID. .withElement(findElement(Locator.ID, "text_input")) // Clear previous input and enter new text into the input element. .perform(clearElement()) .perform(DriverAtoms.webKeys(MACCHIATO)) // Find the "Submit" button and simulate a click using JavaScript. .withElement(findElement(Locator.ID, "submitBtn")) .perform(webClick()) // Find the response element by ID, and verify that it contains the // entered text. .withElement(findElement(Locator.ID, "response")) .check(webMatches(getText(), containsString(MACCHIATO))) } }
Java
public static final String MACCHIATO = "Macchiato"; @Test public void typeTextInInput_clickButton_SubmitsForm() { // Create an intent that displays a web form. Intent webFormIntent = new Intent(); // ... // Lazily launch the Activity with a custom start Intent per test. ActivityScenario.launchActivity(webFormIntent); // Selects the WebView in your layout. If you have multiple WebView objects, // you can also use a matcher to select a given WebView, // onWebView(withId(R.id.web_view)). onWebView() // Find the input element by ID. .withElement(findElement(Locator.ID, "text_input")) // Clear previous input and enter new text into the input element. .perform(clearElement()) .perform(DriverAtoms.webKeys(MACCHIATO)) // Find the "Submit" button and simulate a click using JavaScript. .withElement(findElement(Locator.ID, "submitBtn")) .perform(webClick()) // Find the response element by ID, and verify that it contains the // entered text. .withElement(findElement(Locator.ID, "response")) .check(webMatches(getText(), containsString(MACCHIATO))); }
参考情報
Android のテストで Espresso-Web を使用する方法について詳しくは、以下のリソースをご覧ください。
サンプル
- WebBasicSample: Espresso-Web を使用して
WebView
オブジェクトを操作します。