Z tego artykułu dowiesz się, jak uwzględniać w testach interfejsy API udostępniane przez platformę, które oceniają zachowanie każdego fragmentu.
Fragmenty służą jako kontenery wielokrotnego użytku w aplikacji, dzięki czemu możesz prezentować ten sam układ interfejsu w przypadku różnych działań i konfiguracji układu. Ze względu na wszechstronność fragmentów warto sprawdzić, czy zapewniają one spójne i oszczędne korzystanie z zasobów. Uwaga:
- Twój fragment nie powinien być zależny od określonej aktywności nadrzędnej ani fragmentu.
- Nie należy tworzyć hierarchii widoków danego fragmentu, chyba że jest on widoczny dla użytkownika.
Aby ułatwić skonfigurowanie warunków przeprowadzania tych testów, biblioteka fragment-testing
AndroidaX udostępnia klasę FragmentScenario
do tworzenia fragmentów i zmieniania Lifecycle.State
.
Deklarowanie zależności
Aby użyć FragmentScenario
, zdefiniuj artefakt fragment-testing
w pliku build.gradle
aplikacji za pomocą parametru debugImplementation
, jak w tym przykładzie:
Odlotowy
dependencies { def fragment_version = "1.6.2" debugImplementation "androidx.fragment:fragment-testing:$fragment_version" }
Kotlin
dependencies { val fragment_version = "1.6.2" debugImplementation("androidx.fragment:fragment-testing:$fragment_version") }
Przykłady testowania na tej stronie wykorzystują asercje z bibliotek Espresso i Truth. Informacje o innych dostępnych bibliotekach testowania i asercji znajdziesz w artykule o konfigurowaniu projektu na potrzeby testu AndroidX.
Utwórz fragment
FragmentScenario
stosuje te metody uruchamiania fragmentów w testach:
launchInContainer()
do testowania interfejsu użytkownika fragmentu.FragmentScenario
dołącza fragment do kontrolera widoku głównego aktywności. W przeciwnym razie ta aktywność jest pusta.launch()
, do testowania bez interfejsu użytkownika fragmentu.FragmentScenario
dołącza ten typ fragmentu do pustej aktywności, która nie ma widoku głównego.
Po uruchomieniu jednego z tych typów fragmentów FragmentScenario
przenosi poddany fragment do określonego stanu. Domyślnie ten stan to RESUMED
, ale można go zastąpić za pomocą argumentu initialState
. Stan RESUMED
wskazuje, że fragment jest aktywny i widoczny dla użytkownika. Informacje o elementach interfejsu możesz oceniać za pomocą testów interfejsu Espresso.
W przykładach poniżej pokazujemy, jak uruchomić fragment przy użyciu poszczególnych metod:
przykład uruchamiania InContainer()
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEventFragment() {
// The "fragmentArgs" argument is optional.
val fragmentArgs = bundleOf(“selectedListItem” to 0)
val scenario = launchFragmentInContainer<EventFragment>(fragmentArgs)
...
}
}
przykład uruchomienia()
@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 zawierają zależności, możesz udostępnić testowe wersje tych zależności, podając niestandardowy atrybut FragmentFactory
w metodzie launchInContainer()
lub launch()
.
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEventFragment() {
val someDependency = TestDependency()
launchFragmentInContainer {
EventFragment(someDependency)
}
...
}
}
Więcej informacji o używaniu polecenia FragmentFactory
do określania zależności do fragmentów znajdziesz w artykule Menedżer fragmentów.
Przeprowadź fragment do nowego stanu
W testach interfejsu aplikacji zwykle wystarczy uruchomić testowany fragment i rozpocząć testowanie od stanu RESUMED
. W przypadku bardziej szczegółowych testów jednostkowych możesz też ocenić zachowanie fragmentu podczas przechodzenia z jednego stanu cyklu życia do innego. Stan początkowy możesz określić, przekazując argument initialState
do dowolnej funkcji launchFragment*()
.
Aby przekierować fragment do innego stanu cyklu życia, wywołaj moveToState()
.
Ta metoda obsługuje jako argumenty te stany: CREATED
, STARTED
, RESUMED
i DESTROYED
. Ta metoda symuluje sytuację, w której fragment lub aktywność zawierająca fragment zmienia swój stan z dowolnego powodu.
Poniższy przykład powoduje uruchomienie fragmentu testowego w stanie INITIALIZED
, a następnie przeniesienie 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 z małą ilością zasobów, system może zniszczyć aktywność zawierającą fragment. W takiej sytuacji aplikacja musi odtworzyć fragment, gdy użytkownik powróci do niego.
Aby zasymulować taką sytuację, wywołaj recreate()
:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEventFragment() {
val scenario = launchFragmentInContainer<EventFragment>()
scenario.recreate()
...
}
}
FragmentScenario.recreate()
niszczy fragment i jego host, a następnie je odtwarza. Gdy klasa FragmentScenario
odtworzy testowany fragment, powróci do stanu cyklu życia, w którym znajdował się przed zniszczeniem.
Interakcja z fragmentami interfejsu
Aby aktywować działania interfejsu użytkownika w testowanym fragmencie, użyj mechanizmów dopasowywania widoku Espresso do interakcji 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ę w samym fragmencie, na przykład odpowiedzieć na wybór w menu opcji, możesz zrobić to bezpiecznie, uzyskując odwołanie do fragmentu za pomocą FragmentScenario.onFragment()
i przekazując FragmentAction
:
@RunWith(AndroidJUnit4::class)
class MyTestSuite {
@Test fun testEventFragment() {
val scenario = launchFragmentInContainer<EventFragment>()
scenario.onFragment { fragment ->
fragment.myInstanceMethod()
}
}
}
Przetestuj działania w oknie dialogowym
FragmentScenario
obsługuje też fragmenty okna dialogowego do testowania. Choć fragmenty okien zawierają elementy interfejsu, ich układ jest zapełniany w osobnym oknie, a nie w samej aktywności. Z tego powodu do testowania fragmentów okien użyj FragmentScenario.launch()
.
Ten przykład pozwala przetestować 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())
}
}