Dagger Android, tudo que você precisa entender em português. Parte-2
E ai tudo bem? Dando sequência a parte 2 sobre Dagger Android, na primeira parte vimos os conceitos básicos que você precisa saber, antes de sair usando alguma ferramenta(Você encontra a primeira parte neste blog mesmo)
Então vamos lá ao nosso menu de guia
Os links de toda a sequência você encontra aqui:
______________________________________________________________
Parte 2 — Na segunda parte deste assunto iremos ver na prática como por exemplo:
- Configurando um modulo como exemplo.
- Exemplo de testes unitários deste modulo.
- Exemplo de testes integrados com Espresso.
- Vantagens
- Desvantagens.
- Outros Design Patterns parecidos.
- Outras bibliotecas disponíveis.
- Repositório onde você encontra todos os exemplos.
______________________________________________________________
Configurando o Dagger Android
Bom, vamos agora configurar então o Dagger e usar em nosso projeto.
Adicionando lá no Build.Gradle App
e dentro do dependencies
Em nosso Application, temos que criar lá a inicialização do Dagger.
O nome DaggerAppComponent é porque meu Dagger se chama AppComponent. Então é preciso criar essa classe.
É importante notar que este nosso AppComponent tem noção do Contexto geral da aplicação. Por isso fica fácil também injetar nossos modulos. O gráfico seria assim:
No nosso exemplo vamos criar um LoginComponent.
Vamos visualizar ele como um Sub-componente, pois ele poderá ser usado em diversos lugares a mesma instância dos objetos.
Para usar o Dagger, precisamos sempre falar para ele quem vai usar, no nosso caso a Activity vai precisar das futuras injeções.
E ai no nosso AppComponent, temos que dizer que este é um modulo a ser visto/injetado.
A visão do gráfico de dependências ficaria assim:
Para nosso exemplo, vamos criar então 3 modulos.
- ViewModel
- Repository
- DataSource
No DaggerAndroidActivity, injetamos nosso viewmodel
Pronto. O exemplo esta funcionando.
A visualização do gráfico hoje de nossas dependências ficaria assim:
______________________________________________________________
Exemplo de testes unitários deste modulo
Agora vamos implementar como testar nosso viewmodel. O modo como é feito no Repository e Datasource segue a mesma regra. Logo, vamos apenas implementar como exemplo o viewmodel agora para fins didáticos.
Bom, primeiro temos que ter em mente sobre o InstantTaskExecutorRule
para caso tenhamos tasks ele consiga enxergar isso e não trave nosso teste.
Depois vamos adicionar ao nosso exemplo a biblioteca MocKK
Essa biblioteca é bem legal. Fácil de usar e testar. Deixei comentado em casos que você não precisa saber da resposta para auxiliar você no seus testes também.
Uma vez, vamos validar então na chamada do nosso viewModel quando fizer o doLogin, responder da maneira correta.
Para isso as configurações iniciais são:
Para validar então nosso teste, temos que dizer que o repository vai nos dar uma resposta de acordo com nosso cenário de testes.
E assim nossos UnitTest ficariam:
Nosso resultado:
______________________________________________________________
Exemplo de testes integrados com Espresso
Chegamos em um tópico que eu gosto muito, e foi um pouco não complicado mas difícil de enxergar a primeira vista.
Para primeiro partirmos de Dagger + Espresso. Temos que ter uma pre-configuração no nosso androidTest package.
E no nosso build.gradle App também. Essa é uma sacada que não tem gloria alguma saber, na verdade acho que isso que é o que “emperra” o pessoal na minha opinião quando vai pegar esse assunto.
…
Primeiro, você deve criar uma base para seus testes integrados.
Com um MyCustomTestRunner que estenda AndroidJUnitRunner. E esta implemente seu MyApplication mas no caso, de testes.
Ficaria assim:
Primeiro adicione que seu compilador de AndroidJUnitRunner é o seu MyCustomTestRunner no build.gradle App.
Lá dentro do defaultConfig
Aqui é importante acertar o caminho do seu CustomAndroidJUnitRunner para o seu teste integrado funcionar.
E seu MyTestApplication que vai injetar os modulos fakes de respostas ao devido comportamento que você deseja.
Reparem que eu coloquei em destaque que nesse meu modulo de TestAppComponent eu adiciono um RepositoryFakeModule.
Então assim quando eu iniciar o meu teste integrado. Ele vai me dar o cenário de resposta falsa.
Para terminar então nosso teste de aplicação ficaria assim:
Criei um Gif para você visualizar como funciona o teste.
E é isso, o resto é contigo. Se precisar vai mockando seus cenários nos testes integrados.
______________________________________________________________
Vantagens
Vamos lá, meus pontos de vistas sobre usar Dagger.
- Java/Kotlin — Podemos usar tanto em projetos Java como Kotlin. Querendo ou não ainda muita gente escreve seus projetos em Java.
- Reusabilidade de código
- Fácil de testar
- Manutenção do código se feito de maneira correta tende a ser melhor que uma injeção manual ou outros Design Patterns em minha visão.
- Time do Google pretende colocar no Jetpacket. Isso é importante sim pois mostra que vão procurar dar suporte a essa lib.
- Uma vez entendido o assunto, o stack de erros começa a fazer sentido.
______________________________________________________________
Desvantagens
Como tudo na vida, nada bom é fácil. Então ao meu ver essas são as dificuldades encontradas:
- A curva de aprendizado sem uma documentação em dia se torna uma dor de cabeça, agora com o Hilt novo produto do Android tá ficando mais fácil nesse ponto.
- Anotações de processos tendem a mudar e ai seu código pode vir a quebrar se não ao menos tiver um @Deprecated para te ajudar.
- Realmente, a parte do Espresso não achei muitos exemplos, o único bom mesmo é o codelab lançado pela google aqui neste link: https://codelabs.developers.google.com/codelabs/android-dagger/index.html?index=..%2F..index#13
- Existem outras libs que tendem a ter uma configuração menos complexa ao que parece: Koin é uma delas. Kodein não cheguei a implementar no momento que escrevo esta artigo.
- É necessário ter essa visualização de gráfico de dependências que ainda não é visível o que causa um certo desconforto mental no meu ver. Já vi libs que estão planejando atender a essa necessidade.
______________________________________________________________
Outros Design Patterns parecidos
Bom, como existem vários outros tipos de Design Patterns parecidos é interessante saber a diferença e como justificar sua resposta em usar ou não DI.
São eles:
- Singleton
- ServiceLocator
______________________________________________________________
Singleton:
Singleton é uma instância viva que vai ficar viva enquanto seu app esta funcionando. O que pode deixar ele devagar (Acúmulos de Singletons onde não precisa). Dependência de injeção temos o controle do que é uma fábrica para certos componentes, quando precisamos renovar essas fábricas e quando queremos uma única instância viva dessa classe sim com Singleton Pattern.
Para saber mais segue referências:
https://pt.wikipedia.org/wiki/Singleton
______________________________________________________________
ServiceLocator
Service Locator, também um Design Pattern e tem o problema de uma classe ficar “inchada” com muitos objetos vivos e no fim sua classe de modulo vai ver mais do que precisa. Além das constantes repetições de tipos diferentes vivas como no exemplo Ferrari, Mereces. DI é uma injeção externa, eu digo lá na config que para aquele caso vou precisar disso, disso e acabou.
Para saber mais segue referências:
https://en.wikipedia.org/wiki/Service_locator_pattern
______________________________________________________________
Outras bibliotecas disponíveis
Bom, como dito acima, existem algumas outras bibliotecas. As que eu destaco mais nesse momento seria o Koin. Mas temos também o Kodein. Segue sites deles para mais detalhes.
Link Koin:
Link Kodein:
https://kodein.org/Kodein-DI/?6.5/core
______________________________________________________________
Repositório onde você encontra todos os exemplos
Bom, é isso por essa parte, na próxima vou mostrar como usar isso em um projeto modularizado.
Espero que você tenha gostado, deixa seu joinha ai e vamos para o próximo passo! Valeu, abraço.