1. Mock it with Mockito
Um framework para a construção
de testes unitários melhores
2. Quem sou eu?
● Renan Uchôa,
○ estudante de Engenharia de Software
pela Universidade Federal do Pampa,
○ e Desenvolvedor Java pela uMov.me
Tecnologia S.A.
3. Testes unitários
● Testes unitários servem para verificar
comportamentos de unidade em um
sistema.
● Cada teste deve ser independente e
atômico o suficiente para não depender de
outras unidades que não estiverem sendo
testadas
5. Testes unitários
Testes de caixa-preta verificam as saídas de um sistema com base nas
entradas inputadas, sem um prévio conhecimento sobre a estrutura
do programa.
Testes de caixa-branca verificam comportamentos internos da
estrutura do software para serem abordados nos casos de teste.
6. Testes unitários
E que os testes unitários se encaixam no
conceito de testes de caixa-branca…
… pois permitem ao desenvolvedor construir
testes diretamente baseados no código-fonte e
nos comportamentos apresentados pelas
unidades do software.
7. Testes unitários
Porém apesar de todos os recursos disponíveis
com o JUnit e na linguagem Java, construir
testes realmente úteis ainda é um desafio.
Testes baseados apenas em
retorno de métodos não são
suficientes para cobrir o código.
Falta interagir com o método de
maneira mais livre.
8. Como assim?
● E todas as decisões tomadas no código?
● E os comportamentos implícitos no teste?
● E todo o processo realizado até devolver o
resultado do método?
○ Será que nada disso é relevante para o teste?
● E se o retorno do método não me disser
exatamente o que ele fez?
● E como testar um método sem retorno?
10. Mockito: simpler and better mocking
Mockito permite:
● ter maior flexibilidade na hora de testar
cada comportamento;
● isolar a unidade testada do restante do
código;
● manter os testes legíveis e simples
Keep It Simple, Stupid...
11. Problema
Eu quero testar um comportamento que
inativa um determinado usuário do sistema
após a terceira tentativa de informar a senha.
Porém:
● Não quero que o teste unitário se preocupe
com questões de acesso ao banco de dados;
● Quero verificar apenas se o status foi
alterado e se o método de salvar no banco
de dados foi chamado;
12. Sugestão
Trabalhar com Mockito pode ajudar a resolver
esse problema.
Primeiramente é preciso baixar a biblioteca do
framework em Java através de um .jar
disponível através do link http://code.google.
com/p/mockito/
E não esqueça de importá-la em seu projeto.
14. Resolução
Passos:
● Importar os métodos estáticos da biblioteca para
dentro da classe de testes;
● "Mockar" a classe UserDao, para simular a interação
com o banco de dados;
● Chamar o método login() que será testado a partir da
classe UserService;
● Usar o verify() do Mockito para verificar se método
login() chama o update() na terceira vez que a senha
estiver incorreta.
15. Vantagens
Desta maneira eu garanto que o meu código
invocará o acesso ao banco de dados quando
necessário,…
… porém os meus testes não sofrerão com as
instabilidades do banco de dados, pois não
dependem disso para funcionarem.
16. Assim fica fácil
Com isso manter uma suíte de testes unitários
fica muito mais seguro e tranquilo.
17. Mockito
O mockito é utilizado para sobrescrever
comportamentos dependentes que fogem ao
escopo do teste implementado.
Não faz sentido permitir que problemas
envolvidos com a classe UserDao afetem os
testes realizados sobre a classe UserService.
Usando o Mockito, todos os métodos da classe
UserDao são sobrescritos e retornam 'null'
18. Mockito
Com um "mock" em mãos, podemos verificar quantas
vezes um determinado método foi invocado, manipular o
comportamento informando um retorno "fake" para
simular o funcionamento normal da classe, capturar um
determinado objeto enviado por parâmetro, e etc.
19. Verify
Usando o método verify(), é possível verificar
quantas vezes um determinado método
"mockado" foi chamado durante o teste.
Isso é possível através dos métodos times(),
never(), only(), atLeast(), atMost(), calls(),
atLeastOnce(), com os respectivos
parâmetros.
Ex.: verify(dao, never()).update(any(User.class));
20. Verify
Veja no exemplo abaixo…
● Construímos uma lista com 5
usuários
● Invocamos um serviço que deve
cadasrtrar todos os usuários
listados
● verificamos se o método save foi
chamado 5 vezes passando
qualquer instância da classe
'User'
21. when().thenReturn()
O método when() permite simular retornos de
métodos ou lançamentos de exceção.
Dado que eu não quero que um método seja
executado, porém eu dependo de um retorno
para que o método testado continue
funcionando…
Então eu informo qual objeto deve ser
retornado quando o método for invocado.
22. when().thenReturn()
Dado que o método save() será
invocado pelo service.register()
Quando isso acontecer, ele deve
apenas retornar o mesmo objeto
passado por parâmetro
Sem realizar operações sobre o
banco de dados…
23. any(),…
Existem vários matcher que podem ser usados
para inferir sobre os parâmetros passados nos
métodos…
any(class), anyLong(), anyString(), indicando
que será esperado qualquer parâmetro de um
determinado tipo…
Também é possível dizer o valor exato que
será esperado através do eq()
24. e muito mais…
Para os curiosos, existem também alternativas
para capturar argumentos em chamadas de
métodos, usando o ArgumentCaptor…
… fazer verificações em objetos concretos não
mockados, através do spy()…
e utilizar vários matchers úteis como isNull(),
same(), startsWith(), endsWith(), contains(),
isA(class), doNothing(), doThrow(),…