Testowanie fragmentów

Z tego artykułu dowiesz się, jak uwzględnić w testach interfejsy API udostępniane przez platformę aby ocenić zachowanie poszczególnych fragmentów.

Fragmenty kodu to kontenery wielokrotnego użytku w aplikacji, dzięki którym: ten sam układ interfejsu w wielu różnych działaniach konfiguracji układu. Ze względu na uniwersalność fragmentów ważne jest, w celu potwierdzenia, że działają w sposób spójny i oszczędny. Uwaga:

  • Fragment nie powinien być uzależniony od konkretnej aktywności nadrzędnej ani fragment.
  • Nie należy tworzyć hierarchii widoku fragmentu, chyba że fragment będą widoczne dla użytkownika.

Aby skonfigurować warunki przeprowadzania testów, AndroidX Biblioteka fragment-testing udostępnia FragmentScenario. do tworzenia fragmentów i zmieniania ich Lifecycle.State

.

Deklarowanie zależności

Aby użyć funkcji FragmentScenario, zdefiniuj artefakt fragment-testing-manifest w pliku build.gradle aplikacji za pomocą debugImplementation, a artefakt fragment-testing używający androidTestImplementation, jak pokazano w następujący przykład:

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")
}

Przykłady testowania na tej stronie wykorzystują asercje z Espresso i Truth. Informacje na temat: inne dostępne biblioteki testowania i asercji, zobacz Skonfiguruj projekt na potrzeby Testu AndroidX.

Tworzenie fragmentu

FragmentScenario udostępnia te metody uruchamiania fragmentów w testach:

  • launchInContainer() do testowania interfejsu użytkownika fragmentu. FragmentScenario dołącza makro do głównego kontrolera widoku aktywności. Zawiera aktywność jest pusty.
  • launch() do testowania bez użycia interfejsu użytkownika fragmentu. FragmentScenario dołącza ten typ fragmentu do pustego działania, które nie oznacza, i mamy widok główny.

Po uruchomieniu jednego z tych typów fragmentów FragmentScenario powoduje uruchomienie tagu w trakcie testowania do określonego stanu. Domyślnie ten stan to RESUMED, ale możesz to zastąpić argumentem initialState. RESUMED stan wskazuje, że fragment jest aktywny i widoczny dla użytkownika. Możesz ocenić informacje o jego elementach interfejsu za pomocą interfejsu Espresso

Poniższe przykłady kodu pokazują, jak uruchomić fragment przy użyciu poszczególnych metod:

PrzykładlaunchInContainer()

@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() – przykład

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

Podaj zależności

Jeśli Twoje fragmenty są zależne od zależności, możesz przesłać wersje testowe te zależności, dodając niestandardowy element FragmentFactory do funkcji launchInContainer() lub launch().

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

Więcej informacji o używaniu właściwości FragmentFactory do przekazywania zależności we fragmentach, zobacz Menedżer fragmentów.

Przenieś fragment do nowego stanu

W testach interfejsu aplikacji zwykle wystarczy uruchomić dany fragment. w trakcie testowania i rozpocząć testowanie od stanu RESUMED. Szczegółowo testów jednostkowych, możesz też jednak ocenić zachowanie fragmentu podczas przechodzenia z jednego stanu cyklu życia do drugiego. Możesz określić stanu początkowego, przekazując argument initialState do dowolnej launchFragment*().

Aby przekierować fragment do innego stanu cyklu życia, wywołaj moveToState() Ta metoda obsługuje jako argumenty następujące stany: CREATED, STARTED, RESUMED i DESTROYED. Ta metoda symuluje sytuację gdzie fragment lub działanie zawierające Twój fragment zmienia swój stanu z dowolnego powodu.

Poniższy przykład uruchamia fragment testowy w stanie INITIALIZED i i zmienia go do stanu 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.
        ...
    }
}

Odtwórz fragment

Jeśli aplikacja działa na urządzeniu, na którym brakuje zasobów, system może zniszczyć aktywność zawierającą Twój fragment. Ta sytuacja wymaga od aplikacji odtworzenia fragmentu, gdy użytkownik do niego wróci. Aby zasymulować taką sytuację, zadzwoń pod numer recreate():

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

FragmentScenario.recreate() niszczy fragment i jego hosta, a następnie odtwarza je. Gdy Klasa FragmentScenario odtworzy testowany fragment, czyli fragment wraca do stanu cyklu życia sprzed zniszczenia.

Interakcja z fragmentami interfejsu

Aby aktywować działania interfejsu dla testowanego fragmentu, użyj funkcji Dopasowania widoku Espresso aby wchodzić w interakcję z elementami w widoku:

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

Jeśli musisz wywołać metodę na samym fragmencie, np. odpowiedzieć możesz to zrobić bezpiecznie, pobierając odwołanie do fragmentu za pomocą funkcji FragmentScenario.onFragment() i przekazanie FragmentAction:

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

Testuj działania w oknie dialogowym

FragmentScenario obsługuje też testowanie fragmenty okien. Chociaż fragmenty dialogów elementów interfejsu, ich układ wyświetla się w osobnym oknie, niż w samej aktywności. Z tego powodu użyj funkcji FragmentScenario.launch(), aby przetestować fragmenty okien.

Ten przykład testuje proces zamykania okna:

@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())
    }
}