O guia definitivo sobre dublês de teste no Android — Parte 2: Prática

Mocks, stubs, fakes, dummies e spies no Android: da teoria às (boas) práticas

Phellipe Silva
Android Dev BR
6 min readJan 12, 2021

--

Na primeira parte dessa série sobre dublês de teste, nós aprendemos sobre os conceitos que envolvem a sua utilização. Agora vamos abordar como utilizá-los no mundo Android com alguns exemplos!

Como utilizar dublês de teste no Android?

Quando queremos criar dublês de forma manual não existe muito segredo no Android, basta implementá-los da forma correta como em qualquer outra tecnologia, e utilizar técnicas de injeção de dependências para substituir o colaborador real pelo falso.

As distinções do Android em relação a outras tecnologias aparecem quando começamos a falar sobre ferramentas. No mundo Android podemos utilizar frameworks que sejam compatíveis com as linguagens Java e Kotlin. Dentre os mais famosos podemos citar o Mockito (para Java) e o MockK (para Kotlin).

Vale lembrar que os dublês gerados por ferramentas que normalmente encontramos são os Mocks e os Stubs. Seguem abaixo alguns exemplos de utilização deles. Pelo fato do Kotlin ser linguagem oficial do Android, os exemplos farão uso do MockK, que é um framework específico para gerar dublês nessa linguagem:

Configuração de um Stub utilizando api do MockK.
Configuração de um Mock utilizando api do MockK.

Utilização dos dublês em testes não-instrumentados

Na base da pirâmide encontramos os testes não-instrumentados, que são testes que não fazem uso de emulador ou dispositivo real. Eles deveriam compor a maior quantidade da nossa estratégia de teste por serem mais isolados, rápidos e baratos. Por isso, a utilização de dublês será bem frequente por aqui.

Para demonstrar a utilização dos dublês no mundo Android, vamos ver como seria sua aplicação em uma arquitetura MVVM:

Exemplo de arquitetura MVVM, separando em verde as camadas que dependem da plataforma Android (View e Local Data Source) e em azul as camadas que não dependem da plataforma Android (ViewModel, Repository e Remote Data Source).

Na minha experiência, tenho visto que a escola dos testes solitários são mais comum em projetos Android hoje em dia, por isso tentarei demonstrar uma estratégia de testes que faça uso dessa escola.

Exemplo de como aplicar dublês de teste no MVVM na camada não-instrumentada da pirâmide.

Nessa estratégia acima, utilizamos a seguinte linha de raciocínio:

  • Para testar a camada de View na parte não-instrumentada, provavelmente teremos que fazer um teste com Robolectric, que é uma ferramenta conhecida por ser lenta. Como estamos tratando de um teste custoso, minha recomendação é que não utilizemos dublês para o ViewModel e sim para o Repository. O motivo disso é que os ViewModels (por design) são componentes bem acoplados com as Views e por isso, o comportamento da View seria melhor representado se usássemos ViewModels de verdade. Além disso, não teríamos muito ganho na velocidade se utilizássemos um dublê para o ViewModel, esse teste já seria lento de qualquer forma. Em termos gerais, quanto mais custoso for o teste, mais você deveria se aproximar da realidade, e isso significa que mais código deveria ser coberto no teste e menos dublês deveriam ser utilizados. Nesse exemplo específico, o Repository seria bem substituído por um Stub.
  • Para testar a camada de ViewModel, podemos fazer um teste unitário sem dependência com Android e substituir o Repository por um Stub. Direto ao ponto.
  • Para testar a camada de Repository, também podemos fazer um teste unitário sem dependência com Android. Aqui, substituímos o Local Data Source e o Remote Data Source por Stubs ou Fakes. Também direto ao ponto.
  • Para testar a camada de Remote Data Source, provavelmente teremos que substituir o backend por algum dublê. A forma mais fácil seria criando um Fake utilizando a ferramenta MockWebServer, que simulará um servidor HTTP responsável por retornar respostas pré-configuradas. Testes nessa camada são úteis para comprovar que a serialização das respostas do backend estão ocorrendo corretamente.
  • Para testar a camada de Local Data Source, provavelmente teremos que substituir o banco de dados local por algum dublê. Para nossa sorte, se quisermos fazer esse tipo de teste na camada não-instrumentada, o Robolectric naturalmente cuidará disso para nós, então não precisamos de muitas configurações adicionais. Mesmo assim, acredito que esse tipo de teste possa ser mais útil na parte instrumentada da sua suíte de testes. Para testar a camada de dados em isolamento, prefira fazê-lo com mais confiabilidade.

Lembrando que isso é apenas um exemplo de estratégia. Para testar cada camada da arquitetura, você também pode fazer uso do estilo clássico de testes e utilizar menos dublês se quiser. Tudo depende do que o seu time escolher e do contexto da sua equipe.

Utilização dos dublês em testes instrumentados

Os dublês de teste também são muito importantes para a área instrumentada da pirâmide, porém eles devem ser olhados com um pouco mais de cuidado quando tratamos dessa parte da suíte. Carregar os recursos do Android e executar testes utilizando emulador ou dispositivo real é certamente uma operação custosa, talvez mais custosa do que a grande maioria dos teste não-instrumentado.

Já que teremos um custo elevado para subir esse tipo de infra-estrutura, deveríamos aproveitar o máximo para integrar a maior quantidade de componentes reais possíveis, e por consequência, utilizar menos dublês. Além disso, outro ponto de atenção é que a maioria das ferramentas (como MockK ou Mockito) manipulam bytecode para criar Mocks e Stubs. Como o Android utiliza sua própria máquina virtual e gera bycodes com um formato específico (Dalvik), parte dessas ferramentas possuem limitações para criar dublês nessa camada de teste. Por esses motivos, eu desaconselho utilizar dublês para testes intrumentados. Com exceção a duas situações:

  • Para substituir dependências nas fronteiras de I/O, como backends e bancos de dados, por dublês mais determinísticos e rápidos. Fazendo uso de ferramentas como MockWebServer por exemplo.
  • Ou para substituir ferramentas de terceiros que são de difícil configuração para os testes instrumentados, como por exemplo as soluções do Firebase.
Exemplo de como aplicar dublês de teste na camada instrumentada da pirâmide.

Ferramentas de injeção de dependência (como Dagger, Hilt ou Koin) ou Product Flavours podem ser grandes aliados na utilização de dublês nos testes instrumentados.

Discussões na comunidade Android em relação aos dublês de teste

Como vimos no artigo anterior onde explicamos os conceitos, temos dublês que possuem propósitos semelhantes porém são implementados de maneiras diferentes. É o caso dos Stubs com os Fakes, e dos Mocks com os Spies.

A geração e configuração de Mocks e Stubs são normalmente associadas a ferramentas externas como Mockito e MockK, isso traz uma facilidade muito grande na hora de aplicá-los, porém traz desvantagens por acoplar e expor detalhes de implementação das dependências no teste. Por consequência isso deixará seu teste mais frágil e mais difícil de refatorar. Esse trade-off de simplicidade de configuração VS manutenção do teste já trouxe muitas discussões e publicações interessantes na comunidade de desenvolvimento.

Postagem do Ryan Harter divulgando o seu artigo sobre a substituição de Mocks por Fakes. Nesse caso ele abstraiu o termo Fake como sinônimo de dublê com implementação funcional que substituiria um Mock, talvez o termo Spy fosse mais apropriado no artigo dele.
Postagem do Jake Wharton aparentando ser um seguidor da escola de testes sociáveis e recomendando a utilização de Fakes.
Postagem do Zac Sweers aparentemente insatisfeito com a forma pela qual os dublês de testes são gerados pelo Mockito, que em sua visão, contribui com a fragilidade dos testes.

Conclusão

Agora você deveria ser capaz de responder, ou pelo menos entender, as perguntas feitas na introdução do primeiro artigo:

  • “É só mockar essa dependência que tudo vai dar certo” 🙌
  • “Evite usar Mocks!” 😱
  • “Mocks vs Stub?” ⚔️
  • “Melhor usar Fakes do que Mocks” 🤔

Os dublês de teste (também chamados de forma genérica como Mocks) são muito importantes para sua estratégia de teste. Conheça bem o conceito deles, entenda seus trade-offs e com isso, continue testando sua aplicação Android de maneira automatizada e fácil.

Se você aprendeu algo com esse artigo, deixe suas palmas 👏 Assim eu posso saber que ele foi útil para você. Qualquer feedback ou dúvida, manda no Twitter ou nos comentários desse post. Obrigado!

Referências

Um agracedimento especial a Fred Porciúncula e Angélica Oliveira por revisarem esse artigo.

--

--

Phellipe Silva
Android Dev BR

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