Testowanie aktywności w aplikacji

Aktywności służą jako kontenery dla każdej interakcji użytkownika w aplikacji, dlatego ważne jest, aby przetestować, jak zachowują się aktywności aplikacji podczas zdarzeń na poziomie urządzenia, takich jak:

  • Aktywność aplikacji zostaje przerwana przez inną aplikację, np. aplikację Telefon na urządzeniu.
  • System niszczy i ponownie tworzy aktywność.
  • Użytkownik umieszcza aktywność w nowym środowisku okienkowym, np. w trybie obraz w obrazie lub w trybie wielu okien.

W szczególności ważne jest, aby sprawdzić, czy aktywność zachowuje się prawidłowo w odpowiedzi na zdarzenia opisane w artykule Cykl życia aktywności.

Z tego przewodnika dowiesz się, jak ocenić zdolność aplikacji do zachowania integralności danych i zapewnienia dobrej jakości obsługi, gdy aktywności aplikacji przechodzą przez różne stany w swoich cyklach życia.

Testowanie aktywności w Compose

Podczas testowania aplikacji utworzonej za pomocą Jetpack Compose zwykle używasz createAndroidComposeRule, aby uruchomić aktywność i wchodzić w interakcję z komponentami interfejsu.

Testowanie zdarzeń na poziomie urządzenia, takich jak zmiany konfiguracji lub przejście aktywności do tła albo jej zniszczenie przez system, wymaga jednak bezpośredniego manipulowania cyklem życia aktywności. Aby to zrobić, użyj podstawowej ActivityScenario platformy.

Reguła testu Compose automatycznie opakowuje ten scenariusz i zarządza nim. W tym przewodniku zobaczysz ten wzorzec używany do łączenia nowoczesnego testowania interfejsu z standardowym zarządzaniem cyklem życia:

@get:Rule
val composeTestRule = createAndroidComposeRule<MyActivity>()

@Test fun testEvent() {
    val scenario = composeTestRule.activityRule.scenario

    // ...
}

Sterowanie stanem aktywności

Jednym z kluczowych aspektów testowania aktywności aplikacji jest umieszczanie ich w określonych stanach. Aby zdefiniować tę część testów, użyj instancji ActivityScenario, która jest częścią biblioteki AndroidX Test. Za pomocą tej klasy możesz umieścić aktywność w stanach symulujących zdarzenia na poziomie urządzenia.

ActivityScenario to interfejs API na wielu platformach, którego możesz używać zarówno w lokalnych testach jednostkowych, jak i w testach integracyjnych na urządzeniu. Na prawdziwym lub urządzeniu wirtualnym ActivityScenario zapewnia bezpieczeństwo wątków, synchronizując zdarzenia między wątkiem instrumentacji testu a wątkiem, w którym działa testowana aktywność.

Interfejs API szczególnie dobrze nadaje się do oceny zachowania testowanej aktywności, gdy jest ona niszczona lub tworzona. W tej sekcji przedstawiamy najczęstsze przypadki użycia tego interfejsu API.

Tworzenie aktywności

Aby utworzyć testowaną aktywność, dodaj kod pokazany w tym fragmencie:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
       launchActivity<MyActivity>().use {
       }
    }
}

Po utworzeniu aktywności ActivityScenario przechodzi do stanu RESUMED. Ten stan oznacza, że aktywność jest uruchomiona i widoczna dla użytkowników. W tym stanie możesz wchodzić w interakcję z elementami kompozycyjnymi aktywności za pomocą interfejsów API do testowania Compose.

Google zaleca, aby po zakończeniu testu wywołać metodę close w aktywności. Pozwoli to wyczyścić powiązane zasoby i zwiększyć stabilność testów. ActivityScenario implementuje Closeable, więc możesz zastosować rozszerzenie use, aby aktywność zamykała się automatycznie.

Możesz też użyć createAndroidComposeRule, aby automatycznie uruchamiać aktywność przed każdym testem, obsługiwać zamykanie i przyznawać dostęp do zarówno do metod testowania interfejsu Compose, jak i do podstawowego ActivityScenario. W tym przykładzie pokazujemy, jak zdefiniować regułę i uzyskać z niej instancję scenariusza:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test fun testEvent() {
        val scenario = composeTestRule.activityRule.scenario
    }
}

Przechodzenie aktywności do nowego stanu

Aby przejść do innego stanu, np. CREATED lub STARTED, wywołaj metodę moveToState. Ta czynność symuluje sytuację, w której aktywność jest odpowiednio zatrzymana lub wstrzymana, ponieważ została przerwana przez inną aplikację lub działanie systemu.

Przykład użycia moveToState znajdziesz w tym fragmencie kodu:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use { scenario ->
            scenario.moveToState(State.CREATED)
        }
    }
}

Określanie bieżącego stanu działania

Aby określić bieżący stan testowanej aktywności, pobierz wartość pola state w obiekcie ActivityScenario. Jest to szczególnie przydatne, gdy testowana aktywność przekierowuje do innej aktywności lub sama się kończy, jak pokazano w tym fragmencie kodu:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use { scenario ->
            scenario.onActivity { activity ->
              startActivity(Intent(activity, MyOtherActivity::class.java))
            }

            val originalActivityState = scenario.state
        }
    }
}

Ponowne tworzenie aktywności

Gdy na urządzeniu brakuje zasobów, system może zniszczyć aktywność, co wymaga od aplikacji ponownego utworzenia tej aktywności, gdy użytkownik wróci do aplikacji. Aby zasymulować te warunki, wywołaj metodę recreate:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use { scenario ->
            scenario.recreate()
        }
    }
}

Klasa ActivityScenario zachowuje zapisany stan instancji aktywności i wszystkie obiekty oznaczone adnotacją @NonConfigurationInstance. Te obiekty są wczytywane do nowej instancji testowanej aktywności.

Pobieranie wyników aktywności

Aby uzyskać kod wyniku lub dane powiązane z zakończoną aktywnością, pobierz wartość pola result w obiekcie ActivityScenario. Za pomocą createAndroidComposeRule możesz łatwo wywołać działanie interfejsu, które kończy aktywność, jak pokazano w tym fragmencie kodu:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test fun testResult() {
        composeTestRule.onNodeWithTag("finish_button").performClick()

        val scenario = composeTestRule.activityRule.scenario
        val resultCode = scenario.result.resultCode
        val resultData = scenario.result.resultData
    }
}

Wywoływanie działań w aktywności

Wszystkie metody w ActivityScenario to wywołania blokujące, dlatego interfejs API wymaga, aby były one uruchamiane w wątku instrumentacji.

Aby wywołać działania w testowanej aktywności, użyj interfejsów API do testowania Compose, aby wchodzić w interakcję z elementami kompozycyjnymi:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test fun testEvent() {
        composeTestRule.onNodeWithText("Refresh").performClick()
    }
}

Jeśli jednak musisz wywołać metodę w samej aktywności, możesz to zrobić bezpiecznie za pomocą onActivity:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use { scenario ->
            scenario.onActivity { activity ->
              activity.handleSwipeToRefresh()
            }
        }
    }
}

Dodatkowe materiały

Więcej informacji o testowaniu znajdziesz w tych dodatkowych materiałach:

Dokumentacja