Explorando a pirâmide de testes no Android — Testes não instrumentados na base da pirâmide — parte 2

Phellipe Silva
Android Dev BR
Published in
5 min readMay 27, 2018

No primeiro post sobre pirâmide de testes, tivemos uma visão geral dos conceitos e de como as ferramentas de testes no Android estão distribuídas dentro da pirâmide. Nesse post vamos explorar os testes não instrumentados.

Na base da pirâmide estão os testes mais isolados, rápidos e baratos. Esses devem ser os de maior quantidade na nossa estratégia de teste. As principais vantagens de ter esse tipo de teste são:

  • Feedback rápido na detecção de erros, já que esses testes são curtos e rápidos.
  • Facilidade de identificar o problema ocorrido. Por serem testes mais isolados, torna-se mais fácil identificar onde foi o problema.
  • Facilidade na construção, por serem menores e mais específicos.

Podemos dizer que nessa camada se encontram os testes do pacote test e que eles podem ser categorizados como testes unitários puros e testes com Robolectric.

Exemplo de pirâmide de testes no Android com foco na base

Testes unitários puros

Antes de saber mais sobre esses testes, precisamos entender o conceito de separação de código do framework Android e do código estritamente da linguagem (Kotlin ou Java).

Devemos lembrar que os testes do pacote test não fazem uso de emulador ou smartphone e os recursos do framework Android não vão ser acessíveis por padrão. Esses recursos do Android são aquelas que estão incluídas no SDK da plataforma e possuem dependência direta ou indireta com a classe Context, uma das principais classes do ambiente Android.

Sendo assim, os testes unitários puros são aqueles que não contém qualquer classe do framework Android, podendo ser executados apenas com JUnit e uma ferramenta de mocks.

Abaixo temos um exemplo de teste unitário em Kotlin:

Exemplo de teste unitario: https://gist.github.com/phellipealexandre/ea78d405a16e8e3691eb2f929f43725d.js

Para que esses testes unitários sejam construídos de maneira efetiva é muito importante que sua aplicação tenha uma arquitetura bem estruturada. Dentre as arquiteturas conhecidas nós temos MVP, MVVM, VIPER e MVI.

Abaixo temos um exemplo de como uma arquitetura bem definida poderia nos ajudar:

Exemplo de Arquitetura VIPER customizada no Android

Nesse exemplo de Arquitetura VIPER separamos as camadas em dois grupos, divididos por cores:

Na cor azul estão as camadas que podem ser testadas unitariamente com JUnit + Mocks, pois pertencem apenas ao Java ou Kotlin. Nessa parte é onde normalmente queremos colocar as regras de negócio da nossa aplicação.

Na cor verde estão as camadas que necessitam do framework Android para serem testadas corretamente (logo precisam de um emulador ou um device rodando). Abaixo um pouco mais de detalhes sobre as camadas em verde:

  • Camada View contém classes do Android como Activity, Fragment e outros componentes visuais.
  • Camada Router-Navigator contém classes como Intent que precisam de Context para realizar a navegação.
  • Camada Local Repository pode conter classes como SharedPreferences e outras bibliotecas de armazenamento de dados que podem precisar de Context.

Para facilitar a construção dos testes unitários na base da pirâmide, recomenda-se a utilização dos princípios de injeção de dependências para que seus testes fiquem bem mais simples e isolados. Seguindo esse princípio e possuindo uma arquitetura bem definida, com certeza você estará no caminho certo. 💪

Testes com Robolectric

Para quem não conhece, o Robolectric é um framework de testes que permite que recursos específicos do Android sejam simulados sem a necessidade de carregar um emulador ou dispositivo real. Com ele é possível fazer testes que dependam do Context ou de outras classes do Android de maneira mais rápida e fácil dentro do pacote de testes não instrumentados. Em outras palavras, com Robolectric você consegue testar as classes do grupo verde (da imagem anterior) sem carregar um dispositivo.

O Robolectric realmente faz mágica e já é considerada uma ferramenta madura dentro da comunidade Android. Seus benefícios são inúmeros, porém gostaria de deixar algumas observações que considero importantes:

#1 - Os testes com Robolectric não são estritamente unitários!

Apesar de na página principal do Robolectric ele se definir como "unit test framework", ele pode ou não estar testando unitariamente. Veja um exemplo de um Hello World com Robolectric escrito em Java:

Exemplo de teste com Robolectric. https://gist.github.com/Shebella/aae94c2fdf758296942f

No teste temos uma Activity que contém um Button e um TextView. Ao clicar no botão um resultado vai aparecer no campo de texto. Baseado nesse teste, podemos refletir sobre dois pontos:

  • O teste é muito parecido com um teste de tela (UI)… 🤔
  • Quantas camadas ou classes tivemos que acessar para buscar esse resultado? Não é muito fácil perceber isso nesse teste…

Podemos facilmente pensar em um cenário em que o resultado que aparece no TextView estava armazenado em uma base de dados local. Dessa forma, podemos pensar que um teste que vai da Activity até a base de dados não poderia ser considerado unitário. Como também consigo pensar em um cenário em que o resultado do TextView estava dentro da própria Activity e poderia ser considerado unitário.

Por isso, lembremos do post anterior onde falamos:

O tipo do teste e sua localização na pirâmide será definido pela estratégia de velocidade vs nível de integração e não somente pela ferramenta que escolhemos.

#2 — Os testes de Robolectric não garantem que seu código está bem modularizado ou desacoplado!

Existe o senso comum de que os testes unitários só podem ser feitos quando temos um código modularizado, desacoplado e com uma boa arquitetura. Nesse momento chega o Robolectric que nos ajuda a testar emulando os recursos do Android com um estilo de teste muito parecido com o unitário.

Começamos a construir vários testes sem pensar como está nosso código de produção e aí surge a falsa sensação dentro das equipes de desenvolvimento:

“Se eu consigo fazer testes sem emulador e no pacote test, logo meu código está desacoplado e nossa arquitetura está funcionando bem!”

A afirmação a cima nem sempre é correta, pois pela facilidade que o Robolectric nos dá para construir testes, conseguimos fazê-los mesmo que nosso código esteja acoplado e mal arquitetado.

Em equipes inexperientes, isso pode causar a falsa sensação de que o código que vai para produção está bom mesmo que não esteja. Por isso concluo que o Robolectric é uma ferramenta excelente e ela deve fazer parte da sua pirâmide, porém utilize com cuidado e responsabilidade!

Informação extra sobre Robolectric

No Google IO 2018 foi anunciado que o Robolectric vai fazer parte do framework oficial de testes do Android. Como opinião pessoal, creio que isso é uma evidência de que o próprio Google vê muito potencial nessa ferramenta de testes.

Apresentação do Robolectric como parte do framework oficial de testes do Android no Google IO 2018

Com isso terminamos a segunda parte da série de posts sobre pirâmide de testes. Na próxima parte vamos explorar um pouco mais dos testes instrumentados dentro do Android Studio.

Feedbacks também são muito bem-vindos! Obrigado!

--

--

Phellipe Silva
Android Dev BR

Android engineer and test automation enthusiast. Working @Wise and formerly @ThoughtWorks. Twitter profile: @phellipeafsilva