Espresso-Intents

Espresso-Intents は Espresso の拡張機能であり、テスト対象のアプリによって送信されたインテントの検証とスタブ化を可能にします。 Mockito に似ていますが、Android インテント向けです。

アプリが他のアプリやプラットフォームに機能を委任する場合、Espresso-Intents を使用すると、他のアプリまたはプラットフォームが正しく機能していると仮定して、自分のアプリのロジックに注力できます。Espresso-Intents を使用すれば、送信されるインテントをマッチングして検証できるほか、実際のインテント レスポンスの代わりにスタブ レスポンスを提供することもできます。

プロジェクトへの Espresso-Intents の組み込み

アプリの app/build.gradle ファイルで、dependencies 内に次の行を追加します。

Groovy

androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0'

Kotlin

androidTestImplementation('androidx.test.espresso:espresso-intents:3.4.0')

Espresso-Intents は、Espresso 2.1 以降およびバージョン 0.3 以降の Android テスト ライブラリにのみ対応しているため、これらの行も必ず更新してください。

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')

テストルールの作成

Espresso-Intents テストを作成する前に、IntentsTestRule をセットアップします。これは ActivityTestRule クラスの拡張であり、UI の機能テストで Espresso-Intents API を簡単に使用できるようにします。IntentsTestRule は、@Test アノテーションを付けた各テストの前に Espresso-Intents を初期化し、各テストの実行後に Espresso-Intents をリリースします。

次のコード スニペットは、IntentsTestRule の例を示しています。

Kotlin

@get:Rule
val intentsTestRule = IntentsTestRule(MyActivity::class.java)

Java

@Rule
public IntentsTestRule<MyActivity> intentsTestRule =
    new IntentsTestRule<>(MyActivity.class);

一致

Espresso-Intents には、Hamcrest マッチャーを使用して定義された特定の一致条件に基づいて送信インテントをインターセプトする機能があります。Hamcrest では、次のことができます。

  • 既存のインテント マッチャーを使用する: 最も簡単なオプションであり、ほとんどの場合推奨されます。
  • 独自のインテント マッチャーの実装: 最も自由度の高いオプションです。詳しくは、Hamcrest チュートリアルの「カスタム マッチャーの作成」をご覧ください。

Espresso-Intents には、インテントの検証とスタブ化に、それぞれ intended() メソッドと intending() メソッドが用意されています。どちらも引数として Hamcrest Matcher<Intent> オブジェクトを受け取ります。

次のコード スニペットは、ブラウザを起動する送信インテントと一致する既存のインテント マッチャーを使用するインテント検証を示しています。

Kotlin

assertThat(intent).hasAction(Intent.ACTION_VIEW)
assertThat(intent).categories().containsExactly(Intent.CATEGORY_BROWSABLE)
assertThat(intent).hasData(Uri.parse("www.google.com"))
assertThat(intent).extras().containsKey("key1")
assertThat(intent).extras().string("key1").isEqualTo("value1")
assertThat(intent).extras().containsKey("key2")
assertThat(intent).extras().string("key2").isEqualTo("value2")

Java

assertThat(intent).hasAction(Intent.ACTION_VIEW);
assertThat(intent).categories().containsExactly(Intent.CATEGORY_BROWSABLE);
assertThat(intent).hasData(Uri.parse("www.google.com"));
assertThat(intent).extras().containsKey("key1");
assertThat(intent).extras().string("key1").isEqualTo("value1");
assertThat(intent).extras().containsKey("key2");
assertThat(intent).extras().string("key2").isEqualTo("value2");

インテントの検証

Espresso-Intents は、テスト対象アプリからアクティビティを起動しようとするインテントをすべて記録します。Mockito.verify() に似た intended() メソッドを使用すると、特定のインテントが認識されたことをアサートできます。ただし、Espresso-Intents は、明示的に構成しない限り、インテントへのレスポンスをスタブアウトしません。

次のコード スニペットは、外部の「電話」アクティビティを起動する送信インテントを検証するものの、レスポンスのスタブアウトは行わないテストの例です。

Kotlin

@Test fun validateIntentSentToPackage() {
    // User action that results in an external "phone" activity being launched.
    user.clickOnView(system.getView(R.id.callButton))

    // Using a canned RecordedIntentMatcher to validate that an intent resolving
    // to the "phone" activity has been sent.
    intended(toPackage("com.android.phone"))
}

Java

@Test
public void validateIntentSentToPackage() {
    // User action that results in an external "phone" activity being launched.
    user.clickOnView(system.getView(R.id.callButton));

    // Using a canned RecordedIntentMatcher to validate that an intent resolving
    // to the "phone" activity has been sent.
    intended(toPackage("com.android.phone"));
}

スタブ化

Mockito.when() と同様の intending() メソッドを使用すると、startActivityForResult() で起動されるアクティビティに対するスタブ レスポンスを提供できます。外部アクティビティのユーザー インターフェースを操作したり、テスト対象アクティビティに返される ActivityResult を制御したりすることはできないため、これは外部アクティビティに対して特に便利です。

次のコード スニペットは、サンプルの activityResult_DisplaysContactsPhoneNumber() テストを実装しています。このテストでは、ユーザーがテスト対象のアプリで「連絡先」アクティビティを起動したときに、連絡先の電話番号が表示されることを検証します。

  1. 特定のアクティビティが起動された際に返す結果を準備します。このサンプルテストでは、「連絡先」に送信されたすべてのインテントをインターセプトし、結果コード RESULT_OK を使用して、有効な ActivityResult でレスポンスをスタブ化します。

    Kotlin

    val resultData = Intent()
    val phoneNumber = "123-345-6789"
    resultData.putExtra("phone", phoneNumber)
    val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)
    

    Java

    Intent resultData = new Intent();
    String phoneNumber = "123-345-6789";
    resultData.putExtra("phone", phoneNumber);
    ActivityResult result =
        new ActivityResult(Activity.RESULT_OK, resultData);
    
  2. 「contacts」インテントのすべての呼び出しに応じてスタブ結果オブジェクトを提供するように Espresso に指示します。

    Kotlin

    intending(toPackage("com.android.contacts")).respondWith(result)
    

    Java

    intending(toPackage("com.android.contacts")).respondWith(result);
    
  3. アクティビティの起動に使用されたアクションが、期待されるスタブ結果を生成することを確認します。この例では、「連絡先アクティビティ」の起動時に電話番号「123-345-6789」が返され、表示されることを確認します。

    Kotlin

    onView(withId(R.id.pickButton)).perform(click())
    onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)))
    

    Java

    onView(withId(R.id.pickButton)).perform(click());
    onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)));
    

activityResult_DisplaysContactsPhoneNumber() のテスト全体を次に示します。

Kotlin

@Test fun activityResult_DisplaysContactsPhoneNumber() {
    // Build the result to return when the activity is launched.
    val resultData = Intent()
    val phoneNumber = "123-345-6789"
    resultData.putExtra("phone", phoneNumber)
    val result = Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)

    // Set up result stubbing when an intent sent to "contacts" is seen.
    intending(toPackage("com.android.contacts")).respondWith(result)

    // User action that results in "contacts" activity being launched.
    // Launching activity expects phoneNumber to be returned and displayed.
    onView(withId(R.id.pickButton)).perform(click())

    // Assert that the data we set up above is shown.
    onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)))
}

Java

@Test
public void activityResult_DisplaysContactsPhoneNumber() {
    // Build the result to return when the activity is launched.
    Intent resultData = new Intent();
    String phoneNumber = "123-345-6789";
    resultData.putExtra("phone", phoneNumber);
    ActivityResult result =
        new ActivityResult(Activity.RESULT_OK, resultData);

    // Set up result stubbing when an intent sent to "contacts" is seen.
    intending(toPackage("com.android.contacts")).respondWith(result);

    // User action that results in "contacts" activity being launched.
    // Launching activity expects phoneNumber to be returned and displayed.
    onView(withId(R.id.pickButton)).perform(click());

    // Assert that the data we set up above is shown.
    onView(withId(R.id.phoneNumber)).check(matches(withText(phoneNumber)));
}

参考情報

Android テストで Espresso-Intents を使用する方法について詳しくは、以下のリソースをご覧ください。

サンプル

  • IntentsBasicSample: intended()intending() の基本的な使用方法。
  • IntentsAdvancedSample: カメラを使用してビットマップを取得するユーザーをシミュレートします。