Concrete Logo
Hamburger button

Testes no Android com Espresso – Parte 6

  • Blog
  • 22 de Outubro de 2016
Share

Custom matchers e runtime permissions

Há algum tempo, começamos uma série de posts aqui no Blog sobre testes de Android no Espresso. Se você não estava acompanhando e caiu direto aqui, pode começar neste link.  No último post, a parte 5, aprendemos como fazer asserções e interações em uma recyclerview. Caso queira iniciar a partir deste post, utilize o branch ‘part_5’ do projeto.

Nesta parte do tutorial vamos ver como fazer um matcher customizado e aprender a tratar as runtime permissions. Para isso, foi necessário fazer uma alteração no projeto inicial. Confira esta alteração na classe ImageAndTextView.java (linha 47) e na classe UserDetailsActivity. Entenda bem esta alteração antes de prosseguir.

Primeiro cenário

A UserDetailsActivity possui o seguinte layout:

espresso1

Temos a foto do usuário, o nome, telefone, e-mail e endereço. Este pode ser o primeiro cenário: verificar se todas as informações aparecem na tela. Como é um cenário simples, vou deixar como tarefa para você implementar.

Segundo cenário

Com exceção do nome, o usuário nem sempre terá todos estes dados e, caso ele não tenha telefone, e-mail ou endereço, a mensagem “No info available.” deve aparecer, em vermelho. Conforme imagem abaixo:

Usuário sem e-mail.

Usuário sem e-mail.

Então, outro cenário é verificar se o texto “No info available.” aparece quando o usuário não possui e-mail, telefone ou endereço.

Nada de novo neste teste. Apenas iniciamos a UserDetailsActivity com uma intent que contém um usuário sem e-mail (Mocks.USER_MISSING_INFO) e verificamos se o texto “No info available.” está visível. Porém, não testamos se a cor do texto é vermelha. Para fazer isso, vamos criar um custom matcher.

Crie um pacote matcher e uma classe TextColorMatcher, conforme imagem abaixo:

heitor2

A classe TextColorMatcher ficará assim:

  • Linha 5: declaramos o método withTextColor que recebe uma cor como parâmetro e retorna um Matcher<View>.
  • Linha 6: criamos uma nova instância da classe BoundedMatcher, que permitirá a criação do nosso view matcher.
  • Linha 7: inicializamos a variável que vai armazenar o valor atual da cor do texto do nosso textview.
  • Linhas 8 a 13: sobrescrevemos o método describeTo. É neste método que vamos atribuir ao objeto, do tipo Description, aquilo que será exibido no log caso a asserção falhe.
  • Linhas 16 a 21: sobrescrevemos o método matchesSafely, que é no qual faremos a comparação entre a cor atual do TextView e a cor que esperamos que ele tenha.

Agora é só usarmos o nosso custom matcher no teste:

Para garantir que está funcionando, tente passar uma cor diferente para verificar se o teste falha. Verifique também se a mensagem de erro é a que foi configurada no nosso custom matcher.

Outro detalhe desta tela é que cada informação executa uma ação quando clicada:

  • No número do telefone, uma ligação é feita;
  • No e-mail, uma nova mensagem é aberta para ser enviada ao usuário;
  • No endereço, o Google Maps é aberto e é possível traçar uma rota.

Vamos escrever o teste para o clique no telefone. Os outros dois testes deixo para você implementar.

Runtime Permissions

A partir do Android 6, as permissões são solicitadas em tempo de execução. Isso afeta os nossos testes, pois temos que fazer um tratamento especial para este tipo de situação.

espresso3

Por exemplo, teremos problemas se executarmos um teste como esse:

Em devices anteriores ao Android 6 este teste passa, mas em devices com versão Marshmallow em diante ele vai falhar.

Também não conseguimos fazer o Espresso clicar no botão “Allow”, pois este dialog está fora do contexto da aplicação.

Para este tipo de interação, vamos usar o UiAutomator, pois ele nos permite executar interações com apps do Android. Se você quiser saber melhor a diferença entre Espresso e UiAutomator, dê uma olhada nesta discussão no stackoverflow.

Para começar, adicione esta configuração no seu arquivo build.gradle:

Sincronize o projeto e você provavelmente verá este erro:

Para solucionar este problema, é só seguir a sugestão do próprio log de erro:“use tools:overrideLibrary=”android.support.test.uiautomator.v18 to force usage”.

Primeiro, crie um novo arquivo AndroidManifest.xml dentro da sua pasta androidTest:

novoandroidmanifest

Novo AndroidManifest.xml

Dentro deste arquivo coloque o código abaixo:

Quando ocorrer o merge do Manifest, o erro não ocorrerá novamente.

Eu peguei essa dica desta resposta no stackoverflow. O que acontece é que a lib do UiAutomator tem minSdk 18, e o nosso app tem minSdk 16. Mas como vamos utilizar o UiAutomator somente para os testes, não tem problema sobrescrevermos este valor no Manifest. Fiz os testes com essa alteração em emuladores com API 16+ e tudo funcionou normalmente.

Seguindo com nosso teste, temos o UiAutomator configurado corretamente. Vamos utilizá-lo para interagir com o dialog de permissão do Android.

Esta classe eu encontrei neste gist. Vamos analisá-la por partes:

  • Linha 11: verificamos se a versão do Android é 6 ou mais, e se a permissão que precisamos ainda não foi dada.
  • Linha 13: recuperamos a instância singleton da class UiDevice. Isto permitirá a interação com o dispositivo.
  • Linha 14 a 17: procuramos pelo botão “Allow” do dialog de permissão. Para isso, criamos um objeto UiSelector e chamamos alguns métodos do builder desta classe para configurar nosso objeto. Um destes métodos é o index(int index). Este método vai definir o ID do botão que queremos clicar. No caso do dialog, o botão “Allow” tem valor 1. Se quiséssemos clicar no “Deny” usaríamos o index = 0.
  • Linha 18 e 19: se o botão “Allow” foi encontrado, efetuamos um clique nele.

No nosso teste, vamos chamar o método allowPermissionsIfNeeded doPermissionUtils logo depois do clique no telefone. Ficará assim:

Tente executar o teste, verifique se ele passa. Se algo deu errado, retome os passos anteriores ou deixe um comentário para que eu possa ajudar.

Existem outros cenários a serem testados nesta tela, mas o conhecimento necessário para isso já foi abordado neste tutorial. Então, mãos à obra. ?

Ao final desta etapa, seu código deve estar parecido com o da branch ‘part_6’. Se tiver alguma dúvida ou sugestão, aproveite os campos abaixo. Até a próxima!

É desenvolvedor Android e gostaria de trabalhar em um time ágil de verdade? Clique aqui.