Fragmente testen

In diesem Thema wird beschrieben, wie Sie vom Framework bereitgestellte APIs in Tests einbinden die das Verhalten der einzelnen Fragmente auswerten.

Fragmente dienen als wiederverwendbare Container in Ihrer App, mit denen Sie dasselbe Benutzeroberflächenlayout in einer Vielzahl von Aktivitäten und Layoutkonfigurationen zu erstellen. Aufgrund der Vielseitigkeit der Fragmente ist es wichtig, um zu bestätigen, dass sie eine einheitliche und ressourceneffiziente Nutzung bieten. Beachten Sie Folgendes:

  • Ihr Fragment sollte nicht von einer bestimmten übergeordneten Aktivität oder Fragment.
  • Sie sollten die Ansichtshierarchie eines Fragments nur dann erstellen, wenn das Fragment für den Nutzer sichtbar ist.

Um die Bedingungen für diese Tests zu schaffen, hat die AndroidX- Die fragment-testing-Bibliothek stellt Folgendes bereit: FragmentScenario -Klasse, um Fragmente zu erstellen und ihre Lifecycle.State

Abhängigkeiten deklarieren

Wenn Sie FragmentScenario verwenden möchten, definieren Sie das Artefakt fragment-testing-manifest in Ihrem build.gradle-Datei der Anwendung mit debugImplementation und das fragment-testing-Artefakt mit androidTestImplementation, wie in der folgendes Beispiel:

Groovy

dependencies {
    def fragment_version = "1.8.5"

    debugImplementation "androidx.fragment:fragment-testing-manifest:$fragment_version"

    androidTestImplementation "androidx.fragment:fragment-testing:$fragment_version"
}

Kotlin

dependencies {
    val fragment_version = "1.8.5"

    debugImplementation("androidx.fragment:fragment-testing-manifest:$fragment_version")

    androidTestImplementation("androidx.fragment:fragment-testing:$fragment_version")
}

Verwenden Sie für die Testbeispiele auf dieser Seite Assertions aus dem Espresso und Truth-Bibliotheken. Informationen zur anderen verfügbaren Test- und Assertion-Bibliotheken finden Sie Projekt für AndroidX Test einrichten

Fragment erstellen

FragmentScenario enthält die folgenden Methoden zum Starten von Fragmenten. in Tests:

  • launchInContainer(), zum Testen der Benutzeroberfläche eines Fragments. Mit FragmentScenario wird Folgendes angehängt: auf den Root-Ansicht-Controller einer Aktivität. Diese beinhaltende Aktivität ist ansonsten leer.
  • launch(), ohne die Benutzeroberfläche des Fragments testen. FragmentScenario verknüpft diese Art von Fragment mit einer leeren Aktivität, die nicht eine Stammansicht haben.

Nach dem Start eines dieser Fragmenttypen führt FragmentScenario den das zu testende Fragment in einen bestimmten Zustand versetzt wird. Standardmäßig lautet der Status RESUMED. Sie können dies jedoch mit dem Argument initialState überschreiben. Der Status RESUMED gibt an, dass das Fragment ausgeführt wird und für den Nutzer sichtbar ist. Sie können die Informationen zu UI-Elementen bei Verwendung der Espresso-UI Tests.

Die folgenden Codebeispiele zeigen, wie Sie das Fragment mit den einzelnen Methoden starten:

launchInContainer()-Beispiel

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        // The "fragmentArgs" argument is optional.
        val fragmentArgs = bundleOf(selectedListItem to 0)
        val scenario = launchFragmentInContainer<EventFragment>(fragmentArgs)
        ...
    }
}

launch()-Beispiel

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        // The "fragmentArgs" arguments are optional.
        val fragmentArgs = bundleOf("numElements" to 0)
        val scenario = launchFragment<EventFragment>(fragmentArgs)
        ...
    }
}

Abhängigkeiten angeben

Wenn Ihre Fragmente Abhängigkeiten haben, können Sie Testversionen von diese Abhängigkeiten durch Bereitstellung einer benutzerdefinierten FragmentFactory für den launchInContainer()- oder launch()-Methode.

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        val someDependency = TestDependency()
        launchFragmentInContainer {
            EventFragment(someDependency)
        }
        ...
    }
}

Weitere Informationen zur Verwendung von FragmentFactory zum Bereitstellen von Abhängigkeiten zu Fragmenten, Fragmentmanager:

Fragment in einen neuen Zustand versetzen

In den UI-Tests Ihrer App reicht es normalerweise aus, das Fragment zu starten und mit dem Test ab dem Status RESUMED beginnen. In detaillierterer Einheitentests können Sie auch das Verhalten des Fragments während er von einem Lebenszyklusstatus in einen anderen wechselt. Sie können die indem Sie das Argument initialState an einen der launchFragment*()-Funktionen.

Rufen Sie zum Ändern des Lebenszyklusstatus des Fragments den folgenden Befehl auf: moveToState() Diese Methode unterstützt die folgenden Status als Argumente: CREATED, STARTED, RESUMED und DESTROYED. Diese Methode simuliert eine Situation, wobei das Fragment oder die Aktivität, die Ihr Fragment enthält, seine aus welchem Grund auch immer.

Im folgenden Beispiel wird ein Testfragment mit dem Status INITIALIZED gestartet und und versetzt es in den Status RESUMED:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        val scenario = launchFragmentInContainer<EventFragment>(
            initialState = Lifecycle.State.INITIALIZED
        )
        // EventFragment has gone through onAttach(), but not onCreate().
        // Verify the initial state.
        scenario.moveToState(Lifecycle.State.RESUMED)
        // EventFragment moves to CREATED -> STARTED -> RESUMED.
        ...
    }
}

Fragment neu erstellen

Wenn Ihre App auf einem Gerät mit wenig Ressourcen ausgeführt wird, könnte die Aktivität, die Ihr Fragment enthält, zerstören. Diese Situation erfordert, dass Ihre Anwendung das Fragment neu erstellt, wenn der Nutzer zu ihm zurückkehrt. Rufen Sie recreate() auf, um diese Situation zu simulieren:

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

FragmentScenario.recreate() zerstört das Fragment und seinen Host und erstellt sie neu. Wenn der Parameter Die Klasse FragmentScenario erstellt das zu testende Fragment neu, also das Fragment kehrt in den Lebenszyklusstatus zurück, in dem sie sich vor dem Löschen befand.

Mit UI-Fragmenten interagieren

Verwenden Sie zum Auslösen von UI-Aktionen in Ihrem zu testenden Fragment Espresso-Matcher um mit Elementen in Ihrer Ansicht zu interagieren:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        val scenario = launchFragmentInContainer<EventFragment>()
        onView(withId(R.id.refresh)).perform(click())
        // Assert some expected behavior
        ...
    }
}

Wenn Sie eine Methode für das Fragment selbst aufrufen müssen, Option auswählen, können Sie sicher sein, indem Sie auf das Fragment verweisen, FragmentScenario.onFragment() und die Übergabe einer FragmentAction:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEventFragment() {
        val scenario = launchFragmentInContainer<EventFragment>()
        scenario.onFragment { fragment ->
            fragment.myInstanceMethod()
        }
    }
}

Dialogfeldaktionen testen

FragmentScenario unterstützt auch Tests Dialogfragmente. Obwohl Dialogfragmente UI-Elemente haben, wird das Layout in einem separaten Fenster geöffnet, als in der Aktivität selbst. Verwenden Sie daher FragmentScenario.launch() zum Testen von Dialogfragmenten.

Im folgenden Beispiel wird der Prozess zum Schließen des Dialogfelds getestet:

@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.parentFragmentManager.executePendingTransactions()
                assertThat(fragment.dialog).isNull()
            }
        }

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