Testando sua aplicação
Criando repositórios testáveis
Introdução
Repositórios são classes que tem como objetivo isolar a camada de acesso de dados na sua aplicação, isto é, permitir acesso a fontes de dados remota, locais e cache. Quando falamos em dados locais, também estamos falando de contatos de telefone, imagens, etc… O objetivo desse post é demonstrar a criação de testes para essa camada tão importante, que é a ponte entre o acesso a diferentes tipos de dados e a camada de apresentação.
Como criar testes para o seu repositório?
Primeiro precisamos entender a estrutura de um repositório, se formos aplicar para o nosso cenário onde precisamos acessar uma API do retrofit, então nosso repositório vai acessar apenas a camada de dados remota, sendo apenas um "get". Esse é o momento que muita gente se pergunta: se vamos acessar apenas dados remotos de uma única API, então por que vamos criar um repositório para ser apenas esse "get"?
Analisando esse diagrama, um dos poucos ganhos que podemos perceber é: Isolar na camada de dados o acesso a API, que no caso, está sendo implementada com retrofit. Esse repositório protege o ViewModel/UseCase de certos tipos de alterações, todavia, o repositório ainda fica acoploado a dois pontos: Um Framework e a uma implementação específica.
Com o princípio da inversão de dependência, podemos isolar o framework e a implementação concreta através de um contrato, permitindo maior flexibilidade para o nosso repositório, exemplificado no diagrama abaixo:
Ao olharmos esse diagrama, percebemos que podemos injetar a implementação referente ao contrato de RemoteDataSource
no repositório, isto é, o MoviesApi
foi isolado em uma extremidade e sua comunicação com o repositório é realizada unicamente através do contrato de RemoteDataSource
, gerando desacoplamento com a implementação específica e o framework do retrofit. Esse isolamento possibilita a troca de implementações da RemoteDataSource
sem o risco de quebrar o repositório, reduzindo o impacto dessa modificação.
Mão na massa
Vamos criar o nosso Model, Movie
.
Com nosso model criado, precisamos criar o contrato de acesso a dados remotos, no caso, RemoteDataSource
.
Partindo do TDD, vamos criar nosso teste:
Note que estou injetando o MoviesApi
no construtor da classe. A injeção do mock da classe MoviesApi
com o treino para o mock retornar o objeto esperado dispensa a necessidade do servidor ligado. A classe MoviesApi
já foi testada com o MockWebServer
, então não é necessário efetuar nenhuma validação em seu comportamento aqui nesse teste.
Dica: Sempre que possível, injete a dependência através do construtor, pois isso reduz o acoplamento e facilita os testes. Evite o acoplamento diretamente nas classes como o comando do dagger component.inject(this)
ou o component.get()
do koin.
Após criar as classes para viabilizar a compilação do teste, o teste falhou devido a ausência de implementação das regras.
Implementando nosso remote data source, fazemos uma chamada para API e retornamos a transformação do objeto para List<Movie>
.
É muito importante não vazar detalhes da implementação do MoviesApi
, isto é, o objeto TopRatedMoviesResponse
não pode ter sua visão fora do pacote remote
, pois isso é relacionado apenas a source remota do retrofit. Executamos o teste e agora o feedback foi de que o teste passou:
Precisamos criar um repositório que será responsável por administrar as cahmadas para o data source. Para facilitar o entendimento do teste, encapsularemos dentro de uma estrutura de given-when-then.
Olhando para a estrutura do teste, entendemos que:
- Criamos um mock da chamada realizada pelo RemoteDataSource com o intuito de controlar o resultado esperado pela execução do método.
- Executamos o método a ser testado pelo repositório, o
getTopRatedMovies
. - Validamos o resultado retornado pelo método.
Com isso, criamos as classes para fazer o código compilar e implementamos o repositório chamando o RemoteDataSource
.
Pronto, nosso repositório foi implementado sem nenhum acoplamento com a classe MoviesApi
. O código ficou simples e quando precisarmos implementar cache ou algo do tipo, nossa alteração não vai impactar o código da MoviesApi
e vamos ter os testes automatizados para validar o comportamento implementado anteriormente.
Conclusão
Esse post mostrou como em poucos passos podemos criar um repositório e a camada de acesso a dados remota de forma simples, desacoplada e testáveis.
Gostou do post? Achou interessante? viu algum ponto de melhoria? Comente ou me envie uma mensagem!
Esse foi o segundo post da serie "Testando sua aplicação", onde tem como objetivo mostrar a criação de componentes de arquitetura importantes para o desenvolvimento android junto com seus testes.