Pessoal, lembram do desafio daquele módulo Programação Orientada a Objetos com Java chamado Abstraindo um Bootcamp Usando Orientação a Objetos em Java. Bom eu resolvi aplicar o framework Junit e Mockito para construir os testes unitários deste projeto. Uma premissa que eu assumi ao desenvolver o código, fiz de conta que era legado, ou seja eu iria construir os testes em torno do projeto e não refatorar o projeto em torno dos testes (metodologia TDD). Antes de irmos adiante eu queria explicar um pouco do que se trata o Mockito.
Para relembrar do que se trata o Junit, é um framework que provê ferramentas para testes unitários na linguagem Java, mais detalhes aqui → https://pt.wikipedia.org/wiki/JUnit
Já o framework Mockito é uma espécia de “enganador”, ele implementa uma estrutura que eu configuro via anotations e métodos estáticos que isola o bloco de código que eu estou validando, simulando chamadas e retornos.
Por exemplo, veja a figura 1 abaixo:
FIGURA 1
Eu estou querendo testar os métodos da camada de serviço (onde estão implementadas as regras de negócio do modelo), mas quero simular as chamadas dentro destes métodos feitas a camada repositório (que são os métodos que efetivamente acessam o banco de dados). Para isso eu “engano” a camada de serviço interceptando essas chamadas e enviando uma resposta previamente definida. Dessa forma eu isolo o problema e garanto que se houver algo errado, esse erro não está localizado fora do meu bloco de código domínio do teste unitário.
A anotação @Mock
cria uma instância da classe ProductRepository
“mockeando” os métodos pertinentes, a anotação @InjectMocks
cria uma instancia da classe cujo os métodos quero testar e injeta os “mocks” criados por @Mock
nesta instância. Bom como muitos instrutores da Dio falam, “Show me f* code” (O f* é de minha autoria 😄).
Eu vou a seguir transcrever um trecho de código de um pacote de testes unitários que fiz para testar a camada de serviço associada a uma entidade (Produto) em um projeto usando REST API no Spring Boot.
Primeiro eu crio os mocks e defino a classe que quero injetar os mesmos usando @InjectMocks.
@InjectMocks
private ProductService service;
@Mock
private ProductRepository productRepository;
A seguir eu defino o que eu quero simular da classe mockada, no caso o método produtRepository.findById
(que é chamado pelo método findById()
da classe ProductService
) usando método estático when()…thenReturn()
Mockito.when(productRepository.findById(productExistingId)).thenReturn(Optional.of(product));
E no teste propriamente dito, usando outro método estático fornecido pelo Mockito verify()
, valido se o método foi executado sem problemas e também verifico o número de vezes que o método dummy foi chamado (no caso, espera-se que seja chamado uma única vez, caso contrário o teste falha) :
@DisplayName("003 - findById should return ProductDTO when product id exists.")
@Test
public void findByIdShouldReturnProductDTOWhenIdExists() {
ProductDTO result = service.findById(productExistingId);
Assertions.assertNotNull(result);
Mockito.verify(productRepository,Mockito.times(1)).findById(productExistingId);
}
Veja que para o método da classe Service isso tudo é transparente, mas na realidade o banco de dados nunca foi acessado, a resposta esperada pelo método foi injetada pelo método dummy criado pelo Mockito.
Bom acho que já deu pra ter uma ideia né. Então vamos a implementação que fiz no projeto desafio POO. Eu implementei 7 testes no total:
calcularXp
da classe Curso
calcularXp
da classeDev