Testar as atividades do app

As atividades atuam como contêineres para cada interação do usuário no seu app. Por isso, é importante testar o comportamento delas durante eventos no dispositivo, como:

  • Outro app, como o de telefone, interrompe a atividade.
  • A atividade é destruída e recriada pelo sistema.
  • O usuário move a atividade para um novo ambiente de janelas, como picture-in-picture (PIP) ou várias janelas.

É importante garantir o comportamento correto da atividade em resposta aos eventos descritos no ciclo de vida da atividade.

Este guia descreve como avaliar a capacidade do seu app de manter a integridade dos dados e uma boa experiência do usuário durante as transições de estado das atividades nos ciclos de vida.

Como testar atividades no Compose

Ao testar um app criado com o Jetpack Compose, normalmente você usa createAndroidComposeRule para iniciar a atividade e interagir com os componentes de UI.

No entanto, para testar eventos no nível do dispositivo, como mudanças de configuração ou a atividade sendo colocada em segundo plano ou destruída pelo sistema, é necessário manipular diretamente o ciclo de vida da atividade. Para isso, use o framework ActivityScenario.

A regra de teste do Compose envolve e gerencia automaticamente esse cenário para você. Neste guia, você vai encontrar o seguinte padrão usado para reduzir a diferença entre o teste moderno de UI e o gerenciamento padrão do ciclo de vida:

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

@Test fun testEvent() {
    val scenario = composeTestRule.activityRule.scenario

    // ...
}

Direcionar o estado de uma atividade

Um aspecto importante do teste das atividades do app envolve direcioná-las a estados específicos. Para definir essa parte "determinada" dos testes, use instâncias de ActivityScenario, parte da biblioteca AndroidX Test. Ao usar essa classe, é possível colocar a atividade em estados que simulam eventos no nível do dispositivo.

ActivityScenario é uma API multiplataforma que pode ser usada em testes de unidade local e de integração no dispositivo. Em um dispositivo real ou virtual, a API ActivityScenario fornece segurança na linha de execução, sincronizando eventos entre as linhas de execução da instrumentação do teste e da atividade em teste.

A API é ideal para avaliar como uma atividade em teste se comporta quando é destruída ou criada. Esta seção apresenta os casos de uso mais comuns associados a essa API.

Criar uma atividade

Para criar a atividade em teste, adicione o código mostrado no snippet a seguir:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
       launchActivity<MyActivity>().use {
       }
    }
}

Depois de criá-la, ActivityScenario faz a transição da atividade para o estado RESUMED. Esse estado indica que a atividade está sendo executada e está visível para os usuários. Nele, você pode interagir com os elementos combináveis da atividade usando as APIs de teste do Compose.

O Google recomenda chamar close na atividade após a conclusão do teste. Isso limpa os recursos associados e melhora a estabilidade dos seus testes. ActivityScenario implementa Closeable, então você pode aplicar a extensão use para que a atividade seja fechada automaticamente.

Como alternativa, use createAndroidComposeRule para iniciar automaticamente a Activity antes de cada teste, processar a desmontagem e conceder acesso aos métodos de teste de interface do Compose e ao ActivityScenario subjacente. O exemplo abaixo mostra como definir uma regra e ter uma instância de um cenário a partir dela:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test fun testEvent() {
        val scenario = composeTestRule.activityRule.scenario
    }
}

Direcionar a atividade para um novo estado

Para direcionar a atividade para um estado diferente, como CREATED ou STARTED, chame moveToState. Essa ação simula uma situação em que sua atividade é parada ou pausada, respectivamente, porque é interrompida por outro app ou por uma ação do sistema.

Um exemplo de uso de moveToState aparece no snippet de código a seguir.

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use { scenario ->
            scenario.moveToState(State.CREATED)
        }
    }
}

Determinar o estado atual da atividade

Para determinar o estado atual de uma atividade em teste, verifique o valor do campo state no seu objeto ActivityScenario. É útil verificar o estado de uma atividade em teste se ela redirecionar para outra atividade ou se encerrar sozinha, como demonstrado no snippet de código a seguir:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use { scenario ->
            scenario.onActivity { activity ->
              startActivity(Intent(activity, MyOtherActivity::class.java))
            }

            val originalActivityState = scenario.state
        }
    }
}

Recriar a atividade

Quando um dispositivo está com poucos recursos, o sistema pode destruir uma atividade, exigindo que o app a recrie quando o usuário voltar para ele. Para simular essas condições, chame recreate:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use { scenario ->
            scenario.recreate()
        }
    }
}

A classe ActivityScenario preserva o estado salvo da instância da atividade e quaisquer objetos anotados usando @NonConfigurationInstance. Esses objetos são carregados na nova instância da atividade em teste.

Recuperar resultados de atividades

Para verificar o código de resultado ou os dados associados a uma atividade concluída, verifique o valor do campo result no seu objeto ActivityScenario. Usando o createAndroidComposeRule, é fácil acionar a ação da interface que encerra a atividade, conforme mostrado no snippet de código a seguir:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test fun testResult() {
        composeTestRule.onNodeWithTag("finish_button").performClick()

        val scenario = composeTestRule.activityRule.scenario
        val resultCode = scenario.result.resultCode
        val resultData = scenario.result.resultData
    }
}

Acionar ações na atividade

Todos os métodos em ActivityScenario são chamadas de bloqueio, então a API exige que sejam rodados na linha de execução de instrumentação.

Para acionar ações na atividade em teste, use as APIs de teste do Compose para interagir com seus elementos combináveis:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @get:Rule
    val composeTestRule = createAndroidComposeRule<MyActivity>()

    @Test fun testEvent() {
        composeTestRule.onNodeWithText("Refresh").performClick()
    }
}

No entanto, caso seja necessário chamar um método na própria atividade, será possível fazê-lo de modo seguro usando onActivity:

@RunWith(AndroidJUnit4::class)
class MyTestSuite {
    @Test fun testEvent() {
        launchActivity<MyActivity>().use { scenario ->
            scenario.onActivity { activity ->
              activity.handleSwipeToRefresh()
            }
        }
    }
}

Outros recursos

Para mais informações sobre testes, consulte os seguintes recursos adicionais:

Documentação