É possível testar seu app do Compose com abordagens e padrões bem estabelecidos.
Testar de forma isolada
A ComposeTestRule
permite iniciar uma atividade mostrando qualquer elemento combinável, como
o app completo, uma única tela ou um elemento pequeno. Também é aconselhável
verificar se os elementos que podem ser compostos estão encapsulados corretamente e funcionam
de forma independente, permitindo testes de IU mais fáceis e mais focados.
Isso não significa que você só pode criar testes de IU de unidade. Os testes voltados para partes maiores da IU também são muito importantes.
Acessar a atividade e os recursos depois de definir seu conteúdo
Muitas vezes, é necessário definir o conteúdo que está em teste usando
composeTestRule.setContent
e também acessar recursos de atividade, por
exemplo, para declarar que um texto mostrado corresponde a um recurso de string. No entanto, não será possível chamar setContent
em uma regra criada com createAndroidComposeRule()
se
a atividade já o chamar.
Um padrão comum para fazer isso é criar uma AndroidComposeTestRule
usando
uma atividade vazia, como 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()
}
}
Observe que a ComponentActivity
precisa ser adicionada ao arquivo
AndroidManifest.xml
do app. Ative essa opção adicionando esta dependência ao
módulo:
debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")
Propriedades de semântica personalizadas
É possível criar propriedades de semântica personalizadas para expor informações aos testes.
Para fazer isso, defina uma nova SemanticsPropertyKey
e disponibilize-a usando o
SemanticsPropertyReceiver
.
// Creates a semantics property of type Long.
val PickedDateKey = SemanticsPropertyKey<Long>("PickedDate")
var SemanticsPropertyReceiver.pickedDate by PickedDateKey
Agora use essa propriedade no modificador semantics
:
val datePickerValue by remember { mutableStateOf(0L) }
MyCustomDatePicker(
modifier = Modifier.semantics { pickedDate = datePickerValue }
)
Nos testes, use SemanticsMatcher.expectValue
para declarar o valor da
propriedade:
composeTestRule
.onNode(SemanticsMatcher.expectValue(PickedDateKey, 1445378400)) // 2015-10-21
.assertExists()
Verificar a restauração do estado
Verifique se o estado dos elementos do Compose é restaurado corretamente quando a
atividade ou o processo são recriados. Faça essas verificações sem depender da
recriação de atividades com a classe StateRestorationTester
.
Essa classe permite simular a recriação de um elemento combinável. Ela é
especialmente útil para verificar a implementação de 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.
}
}
Testar diferentes configurações de dispositivo
Os apps Android precisam se adaptar a muitas condições diferentes: tamanhos de janela, localidades,
tamanhos de fonte, temas claros e escuros e muito mais. A maioria dessas condições é
derivada de valores no nível do dispositivo controlados pelo usuário e expostos com a
instância atual de Configuration
. Testar diferentes configurações
diretamente em um teste é difícil, porque o teste precisa configurar propriedades
no nível do dispositivo.
DeviceConfigurationOverride
é uma API somente para teste que permite simular
diferentes configurações de dispositivo de forma localizada para o conteúdo @Composable
em teste.
O objeto complementar de DeviceConfigurationOverride
tem as seguintes
funções de extensão, que substituem as propriedades de configuração no nível do dispositivo:
DeviceConfigurationOverride.DarkMode()
: substitui o sistema para o tema escuro ou claro.DeviceConfigurationOverride.FontScale()
: substitui a escala de fonte do sistema.DeviceConfigurationOverride.FontWeightAdjustment()
: substitui o ajuste de espessura da fonte do sistema.DeviceConfigurationOverride.ForcedSize()
: força uma quantidade específica de espaço, independentemente do tamanho do dispositivo.DeviceConfigurationOverride.LayoutDirection()
: substitui a direção do layout (da esquerda para a direita ou da direita para a esquerda).DeviceConfigurationOverride.Locales()
: substitui a localidade.DeviceConfigurationOverride.RoundScreen()
: substitui se a tela for redonda.
Para aplicar uma substituição específica, encapsule o conteúdo em teste em uma chamada para a
função de nível superior DeviceConfigurationOverride()
, transmitindo a substituição
para aplicar como um parâmetro.
Por exemplo, o código a seguir aplica a
substituição DeviceConfigurationOverride.ForcedSize()
para mudar a densidade
localmente, forçando o elemento combinável MyScreen
a ser renderizado em uma janela
grande na orientação paisagem, mesmo que o dispositivo em que o teste está sendo executado não ofereça suporte a esse tamanho
de janela diretamente:
composeTestRule.setContent { DeviceConfigurationOverride( DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp)) ) { MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping. } }
Para aplicar várias substituições, use
DeviceConfigurationOverride.then()
:
composeTestRule.setContent { DeviceConfigurationOverride( DeviceConfigurationOverride.FontScale(1.5f) then DeviceConfigurationOverride.FontWeightAdjustment(200) ) { Text(text = "text with increased scale and weight") } }
Outros recursos
- Testar apps no Android: a página inicial principal de testes do Android oferece uma visão mais ampla dos conceitos básicos e das técnicas de teste.
- Conceitos básicos de testes:saiba mais sobre os principais conceitos por trás dos testes de um app Android.
- Testes locais:é possível executar alguns testes localmente na sua estação de trabalho.
- Testes instrumentados:é uma boa prática também executar testes instrumentados. Ou seja, testes executados diretamente no dispositivo.
- Integração contínua:a integração contínua permite integrar seus testes ao pipeline de implantação.
- Testar diferentes tamanhos de tela:com alguns dispositivos disponíveis para os usuários, é necessário testar diferentes tamanhos de tela.
- Espresso: embora seja destinado a interfaces baseadas em visualizações, o conhecimento do Espresso ainda pode ser útil para alguns aspectos dos testes do Compose.