Espresso Intents: não é magia, é tecnologia!

Se você leu meu último artigo sobre Testes unitários vs aceitação, já ficou bem claro como é difícil controlar o ambiente de teste.

Existem diversas API’s do próprio Espresso como ActivityMonitor e IdlingResources que nos ajudam nessa empreitada. Utilizando esses dois recursos, já conseguimos criar excelentes testes de aceitação que nos salvam a vida.

Mas, nem tudo é mar de rosas. Imagine um cenário como esse:

Como iremos voltar para nosso app? A não ser que criamos uma implementação da câmera com a “casca” do seu device, fica bem chato testar esse cenário.

E agora, Sica, quem poderá nos ajudar?

É exatamente sobre isso que esse artigo fala: o herói Espresso Intents.

O problema

Um dos principais pilares do nosso querido Android são as Intents. Como o nome diz, uma Intent é quando você tem a intenção (olha só) de fazer algo: um objeto de mensagem que pode ser usado para solicitar uma ação de outro componente de uma aplicação.

Por exemplo, para abrir a câmera, precisamos enviar uma Intent solicitando o app de câmera que o usuário tem no aparelho:

Há três casos de uso fundamentais na utilização das Intent's: para iniciar sua Activity, Service ou enviar um Broadcast. Ou seja, para iniciar (ou utilizar) qualquer coisa, você irá precisar de uma Intent e seus devidos extras (Bundle).

Precisamos repetir esse processo o tempo todo: seja para utilizar aplicações do próprio device ou até para aplicativos de terceiros.

No ambiente de teste

Só de ler o parágrafo acima você já deve ter pensado duas vezes em implementar um teste na sua classe que utiliza esses recursos, né?

Bom, já que qualquer ação para inicializar algo necessita de uma Intent, fica muito difícil você ter certeza, nos seus testes, que as coisas estão acontecendo bem. E é exatamente isso que o Espresso Intents resolve: você consegue controlar todas as Intents que são disparadas (ou recebidas) pela sua aplicação.

Como funciona

O Espresso Intents é uma extensão do Espresso que possibilita você validar e fazer stubbings das Intents que são enviadas e recebidas pela sua aplicação dentro do ambiente de teste.

Sabe o Mockito? Então, é tipo isso, só que pra Intents.

Só de ser possível comparar com o Mockito, já mostra como essa API é valiosa para nossos testes. Vamos entender a sua estrutura:

Adeus ActivityTestRule. Olá IntentsTestRule.

Para iniciar nossa Activity, dentro de um teste anotado, declaramos nossa ActivityTestRule como uma Rule do JUnit e podemos iniciar qualquer Activity que desejamos:

Para inicializar o Espresso Intents, você precisa inicializar a API e liberá-la após o uso:

Mas, pra mim, é bem chato lembrar de fazer isso em todo teste.

Para a nossa alegria, existe a IntentsTestRule que herda da ActivityTestRule.

A IntentsTestRule, por sua vez, facilita a API do Espresso Intents funcionar. Ela inicia o Espresso Intents antes de cada teste anotado com nossa famosa anotação @Test e, quando esse teste terminar, ele irá finalizar a execução de toda a API.

Tá, mas o que isso faz?

Basicamente te torna um mágico das Intents, conseguindo validá-las e controlá-las como um ótimo Merlin.

Você controlando suas Intents

Stubbing de Intent

Agora que você é o Merlin, você tem o poder (lê-se algum programador facilitou isso pra você) de gravar todas as Intents que irão iniciar alguma Activity dentro da sua aplicação.

Já que você tem todas elas, o Espresso Intents tem dois métodos que fazem toda essa mágica.

Utilizando o mesmo exemplo de abrir a câmera, você consegue utilizar o método intending para retornar um resultado desejado:

Validando uma Intent

Nesse caso você estava recebendo uma Intent.

Agora, avalia essa situação:

Se você deixar essa sua Intent vazar, você irá sair do contexto da sua aplicação, onde seus poderes de Merlin surtem efeito, e entrar no ambiente do nosso amiguinho Android, e para interagir com qualquer elemento da tela você irá precisar do UI-Automator. Só de pensar nesse teste eu já abri a boca de sono.

Mas, como iremos testar esse cenário?

Aí que temos o outro método mágico, o intended. Com ele, validar alguma Intent, e a combinando com o método intending, você é capaz de de isolar totalmente seu ambiente de teste :

Agora sim, dá pra testar.

Limitações

No dia a dia, sinto muito a falta de conseguir interceptar uma Intent para abrir outra Activity, e modificar o conteúdo dentro dela, por exemplo:

Isso seria ótimo, já que em um ambiente de CI (emulador) não há imagem alguma. Ou seja, você precisa fornecer essas imagens de alguma maneira.

Mas, atualmente, isso não é suportado, o que nos obriga a fazer uma implementação menos "elegante" .

Projeto de exemplo

Calma que todo esse código não vai ficar só em um post não. Criei esse projeto de exemplo que utiliza algumas situações interessantes e como você pode viajar no uso dessa API.

Conseguiu implementar algo legal? Não hesite em me mandar um pull request!

Sucesso

Aposto que seus testes irão fluir muito melhor com essa extensão maravilhosa do Espresso.

Mas não pense que seus poderes acabaram por aqui: no próximo irei falar sobre o vasto reino da Web e como interagir com elas.

Não esqueça de compartilhar, comentar ou acrescentar em algo nesse post!

Também, me segue lá no Twitter (@rsicarelli)!

Valeu!

Links

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.