Testes no Android com Espresso — parte 3

Testando intents.

No post anterior fizemos nosso primeiro teste na tela de Login. Caso queira iniciar a partir deste post, utilize o branch ‘part_2’ do projeto.

Simulando resultados de intents.

Vamos escrever o teste para o seguinte cenário:

  • Quando username e password não são vazios e o usuário clica no botão de login, o app deve abrir a tela principal (MainActivity).

Poderíamos escrever um teste que preencha os dois campos, clique no botão de login e em seguida verifique se o layout da MainActivity estará visível, algo deste tipo:

Porém, isso é errado por dois motivos. O primeiro pode ser considerado mais uma dica:

Evite fazer testes que façam navegações através do app, inicie as activities diretamente no estado desejado.

O segundo motivo é que a MainActivity faz uma requisição para a API, o que torna este teste dependente de um recurso externo. E aí vai outra dica, que na verdade, deve ser uma regra:

Os testes devem ser isolados de qualquer dependência externa.

Para testarmos se uma activity é iniciada, devemos testar se a intent desta activity é lançada, afinal de contas, quem define qual activity será iniciada é a intent. Para podermos validar a intent, devemos adicionar a seguinte dependência no nosso arquivo build.gradle:

androidTestCompile "com.android.support.test.espresso:espresso-intents:$espressoVersion"

Essa é uma extensão do Espresso que nos permite trabalhar com intents (mais informações neste link).

Antes de escrevermos o teste, vamos analisar o trecho do código que inicia a nossa MainActivity (LoginActivity.java, linha 53).

private void doLogin() {
startActivity(new Intent(this, MainActivity.class));
}

A intent que estamos montando é bem simples, possui apenas o nome da classe (MainActivity.class) e o contexto como parâmetros. Vamos utilizar o nome da classe para validar nossa intent. O nosso teste ficará assim:

Vamos analisar o código:

  • Linha 3: Estamos iniciando a gravação das intents com o método init();
  • Linhas 5 e 6: Nada de novo, apenas preenchendo os campos username e password;
  • Linha 8: Usamos o método IntentMatchers.hasComponent(String className) passando como parâmetro o nome da classe MainActivity, que é a activity que será iniciada;
  • Linha 10: Fazemos o click no botão de login;
  • Linha 12: O método intended(Matcher<Intent> matcher) verifica que o matcher passado como parâmetro é o que a activity em teste irá lançar, garantindo também que esta intent seja única;
  • Linha 14: O método release() limpa os estados das intents.

O que estamos fazendo é falar para o Espresso: “Cara, quando eu preencher estes dois campos e clicar no botão de login, o app deve lançar uma intent para abrir a MainActivity.”. Simples assim.

Se rodarmos o teste, ele passa. Porém ainda há algo errado nele. Repare que a MainActivity ainda abre. E faz sentido, afinal de contas, a única coisa que fizemos foi garantir que a intent lançada é a correta, não fizemos nada para impedir que a MainActivity se inicie.

Para garantir que o nosso teste esteja isolado e evitar a navegação pelo app, vamos simular o resultado desta intent. Refatorando o teste, vai ficar assim:

Foram adicionadas duas linhas:

  • Linha 8: Estamos criando um objeto ActivityResult que irá simular o resultado da activity;
  • Linha 9: Usamos o método intending() para devolver um resultado assim que a intent for lançada.

Um ponto importante na documentação do Espresso sobre esse método:

Note: the destination activity will not be launched.
  • Linha 9: Chamamos o método respondWith(), passando como parâmetro o nosso objeto ActivityResult definido na linha 8.

Novamente, o que estamos falando para o Espresso é: “Quando esta intent for lançada, responda com esse resultado.”, evitando que a MainActivity inicie.

Rode o teste, ele deve passar sem problemas e a MainActivity não será iniciada. Se algo deu errado, retome os passos anteriores ou deixe um comentário abaixo para eu poder te ajudar.

Ótimo, agora que já cobrimos nossa primeira tela com testes, podemos seguir em frente. Antes, verifique se o seu código está parecido com o que está na branch ‘part_3’ do repositório.

Se tiver alguma dúvida, sugestão, ou se encontrou um erro no post, deixe um comentário.

Ir para Parte 4 — mockando requisições para a API >>