Sincronizar seus testes

Por padrão, os testes do Compose são sincronizados com sua IU. Quando você chama uma declaração ou uma ação com o ComposeTestRule, o teste é sincronizado antecipadamente enquanto aguarda até que a árvore da IU fique inativa.

Normalmente, não é necessário fazer nada. No entanto, existem alguns casos extremos que você precisa conhecer.

Quando um teste é sincronizado, o tempo do app Compose é avançado usando um relógio virtual. Isso significa que os testes do Compose não são executados em tempo real, para que possam ser realizados o mais rápido possível.

No entanto, caso você não use os métodos que sincronizam os testes, nenhuma recomposição vai ocorrer, e a IU aparentará estar pausada.

@Test
fun counterTest() {
    val myCounter = mutableStateOf(0) // State that can cause recompositions.
    var lastSeenValue = 0 // Used to track recompositions.
    composeTestRule.setContent {
        Text(myCounter.value.toString())
        lastSeenValue = myCounter.value
    }
    myCounter.value = 1 // The state changes, but there is no recomposition.

    // Fails because nothing triggered a recomposition.
    assertTrue(lastSeenValue == 1)

    // Passes because the assertion triggers recomposition.
    composeTestRule.onNodeWithText("1").assertExists()
}

Esse requisito se aplica apenas a hierarquias do Compose, e não ao restante do app.

Desativar a sincronização automática

Quando você chama uma declaração ou ação usando ComposeTestRule, como assertExists(), seu teste é sincronizado com a IU do Compose. Em alguns casos, pode ser necessário interromper essa sincronização e controlar o relógio. Por exemplo, você pode controlar o tempo para fazer capturas de tela precisas de uma animação em um ponto em que a IU ainda estaria ocupada. Para desativar a sincronização automática, defina a propriedade autoAdvance em mainClock como false:

composeTestRule.mainClock.autoAdvance = false

Normalmente, isso fará com que o tempo seja avançado. É possível avançar exatamente um frame com advanceTimeByFrame() ou um intervalo específico com advanceTimeBy():

composeTestRule.mainClock.advanceTimeByFrame()
composeTestRule.mainClock.advanceTimeBy(milliseconds)

Recursos inativos

O Compose pode sincronizar testes e a IU para que todas as ações e declarações sejam executadas em estado inativo enquanto estão aguardando ou avançando o relógio conforme necessário. No entanto, algumas operações assíncronas com resultados que afetam o estado da IU podem ser executadas em segundo plano enquanto não afetam os testes.

Crie e registre esses recursos de inatividade no teste para que eles sejam considerados ao decidir se o app em teste está ocupado ou inativo. Não é necessário fazer nada, a menos que você precise registrar outros recursos de inatividade, por exemplo, executar um job em segundo plano que não esteja sincronizado com o Espresso ou o Compose.

Essa API é muito semelhante aos Recursos de inatividade do Espresso, usados para indicar se o assunto em teste está inativo ou ocupado. Use a regra de teste do Compose para registrar a implementação do IdlingResource.

composeTestRule.registerIdlingResource(idlingResource)
composeTestRule.unregisterIdlingResource(idlingResource)

Sincronização manual

Em alguns casos, você precisa sincronizar a IU do Compose com outras partes do teste ou do app sendo testado.

A função waitForIdle() aguarda que o Compose esteja inativo, mas depende da propriedade autoAdvance:

composeTestRule.mainClock.autoAdvance = true // Default
composeTestRule.waitForIdle() // Advances the clock until Compose is idle.

composeTestRule.mainClock.autoAdvance = false
composeTestRule.waitForIdle() // Only waits for idling resources to become idle.

Em ambos os casos, waitForIdle() também aguarda transmissões de layout e desenho pendentes.

Além disso, você pode avançar o relógio até que uma determinada condição seja atendida com advanceTimeUntil().

composeTestRule.mainClock.advanceTimeUntil(timeoutMs) { condition }

A condição especificada precisa ser verificar o estado que pode ser afetado por esse relógio. Isso só funciona com estados no Compose.

Aguardar condições

Qualquer condição que dependa de trabalho externo, como o carregamento de dados ou a medição ou o desenho do Android (ou seja, medição ou desenho externos ao Compose), precisa usar um conceito mais geral, como waitUntil():

composeTestRule.waitUntil(timeoutMs) { condition }

Também é possível usar qualquer um dos ajudantes waitUntil:

composeTestRule.waitUntilAtLeastOneExists(matcher, timeoutMs)

composeTestRule.waitUntilDoesNotExist(matcher, timeoutMs)

composeTestRule.waitUntilExactlyOneExists(matcher, timeoutMs)

composeTestRule.waitUntilNodeCount(matcher, count, timeoutMs)

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.