Android 11 のデベロッパー プレビューが公開されました。ぜひお試しのうえ、フィードバックをお寄せください

アプリのフラグメントをテストする

フラグメントはアプリ内の再利用可能なコンテナとして機能し、同じユーザー インターフェース レイアウトを、さまざまなアクティビティおよびレイアウト構成で表示できます。フラグメントの多様性を考慮して、一貫性のあるリソース効率のよいエクスペリエンスが提供されているかどうかを検証することが重要です。

  • フラグメントの外観は、より大きな画面サイズや横向きデバイスの画面の向きをサポートするレイアウトを含め、すべてのレイアウト構成にわたって一貫している必要があります。
  • フラグメントがユーザーに表示されない限り、フラグメントのビュー階層を作成しないでください。

このドキュメントでは、フレームワークが提供する API を各フラグメントの動作を評価するテストに含める方法を説明します。

フラグメントの状態を変更する

AndroidX に用意されているフラグメントの作成とその状態を変更するための FragmentScenario ライブラリは、これらのテストの実行条件をセットアップする際に役立ちます。

testing アーティファクトの場所を構成する

FragmentScenario を意図したとおりに使用するには、次のコード スニペットに示すように、アプリのテスト APK で fragment-testing アーティファクトを定義します。

app/build.gradle

    dependencies {
        def fragment_version = "1.0.0"
        // ...
        debugImplementation 'androidx.fragment:fragment-testing:$fragment_version'
    }
    

このライブラリの現在のバージョンを確認するには、バージョンのページでフラグメントに関する情報をご覧ください。

フラグメントを作成する

FragmentScenario には、次のタイプのフラグメントを起動するためのメソッドが含まれています。

このメソッドは、次のタイプのフラグメントもサポートします。

  • グラフィカル フラグメント: ユーザー インターフェースが含まれます。このタイプのフラグメントを起動するには、launchFragmentInContainer() を呼び出します。このフラグメントは、FragmentScenario によってアクティビティのルート ビュー コントローラに添付されます。それ以外の場合、このアクティビティは空です。
  • 非グラフィカル フラグメント(ヘッドレス フラグメントと呼ばれることもあります): 複数のアクティビティに含まれる情報に対する短時間の処理が保存または実行されます。このタイプのフラグメントを起動するには、launchFragment() を呼び出します。 このタイプのフラグメントは、FragmentScenario によって完全に空のアクティビティ(ルートビューを持たないアクティビティ)に添付されます。

これらのフラグメント タイプのいずれかを起動すると、FragmentScenario によってテスト中のフラグメントが RESUMED 状態になります。この状態は、フラグメントが実行中であることを示します。グラフィカル フラグメントをテストする場合、そのフラグメントはユーザーにも表示されるため、Espresso UI テストを使用してその UI 要素に関する情報を評価できます。

次のコード スニペットは、各タイプのフラグメントを起動する方法を示しています。

グラフィカル フラグメントの例

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEventFragment() {
            // The "fragmentArgs" and "factory" arguments are optional.
            val fragmentArgs = Bundle().apply {
                putInt("selectedListItem", 0)
            }
            val factory = MyFragmentFactory()
            val scenario = launchFragmentInContainer<MyFragment>(
                    fragmentArgs, factory)
            onView(withId(R.id.text)).check(matches(withText("Hello World!")))
        }
    }
    

非グラフィカル フラグメントの例

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEventFragment() {
            // The "fragmentArgs" and "factory" arguments are optional.
            val fragmentArgs = Bundle().apply {
                putInt("numElements", 0)
            }
            val factory = MyFragmentFactory()
            val scenario = launchFragment<MyFragment>(fragmentArgs, factory)
        }
    }
    

フラグメントを再作成する

デバイスのリソースが少ないと、フラグメントを含むアクティビティが破棄される可能性があるため、ユーザーがアプリに戻ったときにアプリによるフラグメントの再作成が必要になる場合があります。この状況をシミュレートするには、recreate() を呼び出します。

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEventFragment() {
            val scenario = launchFragmentInContainer<MyFragment>()
            scenario.recreate()
        }
    }
    

FragmentScenario クラスでテスト中のフラグメントが再作成されると、フラグメントは再作成される前のライフサイクル状態に戻ります。

フラグメントを新しい状態にする

アプリの UI テストでは、通常、テスト中のフラグメントを起動して再作成するだけで十分です。しかし、より詳細なユニットテストでは、フラグメントのライフサイクル状態が変わるときにそのフラグメントの動作を評価することがあります。

フラグメントを別のライフサイクル状態にするには、moveToState() を呼び出します。このメソッドでは、CREATEDSTARTEDRESUMEDDESTROYED の各状態が引数としてサポートされます。このアクションは、フラグメントを含むアクティビティの状態が、別のアプリまたはシステムのアクションによって中断されたために変わる状況をシミュレートします。

moveToState() の使用例を次のコード スニペットに示します。

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEventFragment() {
            val scenario = launchFragmentInContainer<MyFragment>()
            scenario.moveToState(State.CREATED)
        }
    }
    

フラグメントでアクションをトリガーする

テスト中のフラグメントでアクションをトリガーするには、Espresso ビュー マッチャーを使用してビュー内の要素を操作します。

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEventFragment() {
            val scenario = launchFragmentInContainer<MyFragment>()
            onView(withId(R.id.refresh))
                    .perform(click())
        }
    }
    

オプション メニューの選択内容に応答するなど、フラグメント自体でメソッドを呼び出す必要がある場合は、FragmentAction を実装すると安全に呼び出すことができます。

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testEventFragment() {
            val scenario = launchFragmentInContainer<MyFragment>()
            scenario.onFragment(fragment ->
                fragment.onOptionsItemSelected(clickedItem) {
                    // Update fragment's state based on selected item.
                }
            }
        }
    }
    

ダイアログ アクションをテストする

FragmentScenario では、ダイアログのテストもサポートされています。ダイアログはグラフィカル フラグメントのインスタンスですが、ダイアログの要素はダイアログを起動するアクティビティではなく、ダイアログ自体で設定されるように launchFragment() メソッドを使用します。

次のコード スニペットでは、ダイアログ消去プロセスをテストします。

    @RunWith(AndroidJUnit4::class)
    class MyTestSuite {
        @Test fun testDismissDialogFragment() {
            // Assumes that "MyDialogFragment" extends the DialogFragment class.
            with(launchFragment<MyDialogFragment>()) {
                onFragment { fragment ->
                    assertThat(fragment.dialog).isNotNull()
                    assertThat(fragment.requireDialog().isShowing).isTrue()
                    fragment.dismiss()
                    fragment.requireFragmentManager().executePendingTransactions()
                    assertThat(fragment.dialog).isNull()
                }

                // Assumes that the dialog had a button
                // containing the text "Cancel".
                onView(withText("Cancel")).check(doesNotExist())
            }
        }
    }