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:
DeviceConfigurationOverride.DarkMode()
: zastępuje ustawienia systemowe ciemnym lub jasnym motywem.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 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.