Typowe wzorce

Aplikację napisaną w Compose możesz testować za pomocą sprawdzonych metod i wzorców.

Testowanie w izolacji

ComposeTestRule umożliwia rozpoczęcie aktywności wyświetlającej dowolny element kompozycyjny: całą aplikację, pojedynczy ekran lub mały element. Warto też sprawdzić, czy funkcje kompozycyjne są prawidłowo hermetyzowane i działają niezależnie, co ułatwia i usprawnia testowanie interfejsu.

Nie oznacza to, że należy tworzyć tylko jednostkowe testy interfejsu. Bardzo ważne jest też określanie zakresu testów interfejsu, które obejmują większe części interfejsu.

Dostęp do aktywności i zasobów po ustawieniu własnych treści

Często musisz ustawić testowaną treść za pomocą atrybutu composeTestRule.setContent, a także uzyskać dostęp do zasobów aktywności, np. aby sprawdzić, czy wyświetlany tekst pasuje do zasobu w postaci ciągu znaków. Nie możesz jednak wywołać funkcji setContent w przypadku reguły utworzonej za pomocą funkcji createAndroidComposeRule(), jeśli aktywność już ją wywołuje.

Często stosowanym sposobem jest utworzenie AndroidComposeTestRule za pomocą pustej aktywności, np. ComponentActivity.

class MyComposeTest {

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

    @Test
    fun myTest() {
        // Start the app
        composeTestRule.setContent {
            MyAppTheme {
                MainScreen(uiState = exampleUiState, /*...*/)
            }
        }
        val continueLabel = composeTestRule.activity.getString(R.string.next)
        composeTestRule.onNodeWithText(continueLabel).performClick()
    }
}

Pamiętaj, że ComponentActivity musi zostać dodany do pliku AndroidManifest.xml aplikacji. Aby to zrobić, dodaj tę zależność do modułu:

debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")

Właściwości semantyczne niestandardowe

Możesz tworzyć niestandardowe właściwości semantyczne, aby udostępniać informacje na potrzeby testów. Aby to zrobić, zdefiniuj nowy SemanticsPropertyKey i udostępnij go za pomocą SemanticsPropertyReceiver.

// Creates a semantics property of type Long.
val PickedDateKey = SemanticsPropertyKey<Long>("PickedDate")
var SemanticsPropertyReceiver.pickedDate by PickedDateKey

Teraz użyj tej właściwości w modyfikatorze semantics:

val datePickerValue by remember { mutableStateOf(0L) }
MyCustomDatePicker(
    modifier = Modifier.semantics { pickedDate = datePickerValue }
)

W testach użyj SemanticsMatcher.expectValue, aby potwierdzić wartość właściwości:

composeTestRule
    .onNode(SemanticsMatcher.expectValue(PickedDateKey, 1445378400)) // 2015-10-21
    .assertExists()

Sprawdzanie przywracania stanu

Sprawdź, czy stan elementów Compose jest prawidłowo przywracany po ponownym utworzeniu aktywności lub procesu. Przeprowadzaj takie testy bez polegania na ponownym tworzeniu aktywności za pomocą klasy StateRestorationTester.

Ta klasa umożliwia symulowanie ponownego tworzenia komponentu. Jest to szczególnie przydatne do weryfikowania implementacji rememberSaveable.


class MyStateRestorationTests {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun onRecreation_stateIsRestored() {
        val restorationTester = StateRestorationTester(composeTestRule)

        restorationTester.setContent { MainScreen() }

        // TODO: Run actions that modify the state

        // Trigger a recreation
        restorationTester.emulateSavedInstanceStateRestore()

        // TODO: Verify that state has been correctly restored.
    }
}

Testowanie różnych konfiguracji urządzeń

Aplikacje na Androida muszą dostosowywać się do wielu zmieniających się warunków: rozmiarów okien, ustawień regionalnych, rozmiarów czcionek, ciemnych i jasnych motywów i innych. Większość tych warunków pochodzi z wartości na poziomie urządzenia kontrolowanych przez użytkownika i udostępnianych w bieżącej instancji Configuration. Testowanie różnych konfiguracji bezpośrednio w teście jest trudne, ponieważ test musi konfigurować właściwości na poziomie urządzenia.

DeviceConfigurationOverride to interfejs API przeznaczony tylko do testów, który umożliwia symulowanie różnych konfiguracji urządzeń w sposób zlokalizowany na potrzeby testowanej treści @Composable.

Obiekt towarzyszący DeviceConfigurationOverride ma te funkcje rozszerzające, które zastępują właściwości konfiguracji na poziomie urządzenia:

Aby zastosować konkretne zastąpienie, umieść testowaną treść w wywołaniu funkcji najwyższego poziomu DeviceConfigurationOverride(), przekazując zastąpienie do zastosowania jako parametr.

Na przykład poniższy kod stosuje zastąpienie DeviceConfigurationOverride.ForcedSize(), aby lokalnie zmienić gęstość, wymuszając renderowanie funkcji kompozycyjnej MyScreen w dużym oknie w orientacji poziomej, nawet jeśli urządzenie, na którym jest uruchamiany test, nie obsługuje bezpośrednio tego rozmiaru okna:

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
    ) {
        MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
    }
}

Aby zastosować kilka zastąpień jednocześnie, użyj elementu DeviceConfigurationOverride.then():

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.FontScale(1.5f) then
            DeviceConfigurationOverride.FontWeightAdjustment(200)
    ) {
        Text(text = "text with increased scale and weight")
    }
}

Dodatkowe materiały

  • Testowanie aplikacji na Androida: główna strona docelowa dotycząca testowania na Androidzie zawiera szersze omówienie podstaw testowania i technik testowania.
  • Podstawy testowania: dowiedz się więcej o podstawowych koncepcjach związanych z testowaniem aplikacji na Androida.
  • Testy lokalne: niektóre testy możesz przeprowadzać lokalnie, na własnej stacji roboczej.
  • Testy z użyciem instrumentacji: warto też przeprowadzać testy z użyciem instrumentacji. Są to testy, które są przeprowadzane bezpośrednio na urządzeniu.
  • Ciągła integracja: Ciągła integracja umożliwia zintegrowanie testów z potokiem wdrażania.
  • Testowanie różnych rozmiarów ekranu: użytkownicy mają do dyspozycji wiele urządzeń, dlatego warto testować różne rozmiary ekranu.
  • Espresso: chociaż Espresso jest przeznaczony do interfejsów opartych na widokach, wiedza na jego temat może być przydatna w przypadku niektórych aspektów testowania Compose.