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 komponent 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ą pustego działania, 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 testom.
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()
Weryfikowanie 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 jest wyprowadzana 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:
DeviceConfigurationOverride.DarkMode(): zastępuje ustawienia systemowe i włącza ciemny lub jasny motyw.DeviceConfigurationOverride.FontScale(): zastępuje skalę czcionki systemowej.DeviceConfigurationOverride.FontWeightAdjustment(): zastępuje dostosowanie grubości czcionki systemowej.DeviceConfigurationOverride.ForcedSize(): wymusza określoną ilość miejsca niezależnie od rozmiaru urządzenia.DeviceConfigurationOverride.LayoutDirection(): zastępuje layout direction (od lewej do prawej lub od prawej do lewej).DeviceConfigurationOverride.Locales(): zastępuje język.DeviceConfigurationOverride.RoundScreen(): zastępuje wartość, jeśli ekran jest okrągły.
Aby zastosować konkretne zastąpienie, umieść testowaną treść w wywołaniu funkcji najwyższego poziomu DeviceConfigurationOverride(), przekazując jako parametr zastąpienie, które ma zostać zastosowane.
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 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 przeznaczone do interfejsów opartych na widokach, wiedza na jego temat może być przydatna w przypadku niektórych aspektów testowania Compose.