Mockito: como utilizar de maneira simples
Tags: mockito, java, testing, test
Published: 2021-03-09 23:59:51

Eu utilizo o _Mockito_ tem algum tempo e é uma ferramenta muito poderosa. Sem ele criar testes seria muito mais verboso e de certa forma complicado.
Depois de entender bem o conceito e a forma de utilizar o desenvolvimento de testes fica muito mais rápido e assertivo.

##O que é o Mockito?
O Mockito é um framework de Test and Spy e o seu principal objetivo é simular a instancia de classes e comportamento de métodos. Ao mockar uma dependência com o mockito, eu faço com que a classe que vai ser testada simule o método testado e suas dependências. Durante o mock eu posso configurar retorno e ações de acordo com o necessidade do teste.

## Principais funções
* **Mock**: cria uma instancia de uma classe, porém Mockada. Se você chamar um metodo ele não irá chamar o metodo real, a não ser que você queira.
* **Spy**: cria uma instancia de uma classe, que você pode mockar ou chamar os metodos reais. É uma alternativa ao InjectMocks, quando é preciso mockar metodos da propria classe que esta sendo testada.
* **InjectMocks**: criar uma intancia e injeta as dependências necessárias que estão anotadas com @Mock.
* **Verify**: verifica a quantidade de vezes e quais parametros utilizados para acessar um determinado metodo.
* **When**: Após um mock ser criado, você pode configurar ações na chamada e o retorno.
* **Matchers**: permite a verificação por meio de matchers de argumentos (anyObject(), anyString() …)

### Criando um mock
Há duas formas de criar um mock usando o _mockito_ por meio de um método estático ou com a anotação @Mock
* Utilizando método statico
```
var EmployeeRepository = Mockito.mock(EmployeeRepository.class)
```
* anotação @Mock
```
@Mock
private	EmployeeRepository employeeRepository;
```
### Configurando a classe testada
Ao declarar a classe vamos anotar ela com @InjectMocks. O Mockito vai criar uma instância real dessa classe e injetar todos os objetos @ Mock que foram declarados na classe de teste.
```
@InjectMocks
private EmployeeController employeeController;
```
### Hibilitando as anotações
Para essas anotações @Mock e @InjectMocks funcionar, é preciso habilita-las. existem duas formas:
* Anotando a classe de teste com @RunWith(MockitoJUnitRunner.class)
```
@RunWith(MockitoJUnitRunner.class)
public class EmployeeControllerTest {}
```
* Usando o MockitoAnnotations.initMocks () antes dos testes

```
@Before
public void setup() {
    MockitoAnnotations.initMocks(this);
}
```

### Testando um metodo void
O método que vai ser testado:
```
@DeleteMapping("/employees/{id}")
public void deleteEmployee(@PathVariable Long id) {
    repository.deleteById(id);
}
```
O teste
```
@Test
public void deleteEmployee() {
        employeeController.deleteEmployee(1L);
	Mockito.verify(employeeRepository, Mockito.times(1)).deleteById(1L);
}
```
Primeiro chamamos o método que vai ser testado e passamos os 
parâmetros necessários.
Em seguida usamos o _Mockito.verify_ para verificar se durante a execução das classes mocadas foi chamado o método em questão.
Podemos verificar varias coisas com _Mockito.verify_ numero de vezes que executou, parâmetros recebidos e etc.

### @Spy Annotation
Usamos o @Spy para espionar uma instância existente.
No exemplo abaixo eu adicionei dois elementos a uma lista e em seguida verifiquei se os elementos foram mesmo inseridos.

```
@Test
public void spyTest() {
		List<Employee> employees = Mockito.spy(new ArrayList<Employee>());
		Employee one = new Employee("Bilbo Baggins", "burglar");
		Employee two = new Employee("Frodo Baggins", "thief");
		
		employees.add(one);
		employees.add(two);
		
		Mockito.verify(employees).add(one);
	    Mockito.verify(employees).add(two);
	    assertEquals(2, employees.size());

	    Mockito.doReturn(100).when(employees).size();
	    assertEquals(100, employees.size());
	}
	
```
* employees.add() para adicionar elementos a employees.
* employees.size() para retornar 100 em vez de 2 usando Mockito.doReturn()

### Método when
Através dele é possível simular chamadas a recursos externos a classe, como acesso a um banco de dados por exemplo, sem se preocupar como funcionará essa consulta, não é responsabilidade desse teste.
A sintaxe do when é essa:
* when(employeeRepository.save(Mockito.any(Employee.class))).thenReturn(employee);
* when(employeeRepository.save(Mockito.eq(employeeInput))).thenReturn(employee);
* when(employeeRepository.save(Mockito.any())).thenReturn(employee);

```
@Test
public void newEmployee_test() {
		Employee employee = EmployeeTest.create();
		when(employeeRepository.save(Mockito.any(Employee.class))).thenReturn(employee);
		ResponseEntity<Employee> newEmployee = employeeController.newEmployee(employee);
		assertEquals(employee.getName(), newEmployee.getBody().getName());
		assertEquals(employee.getRole(), newEmployee.getBody().getRole());
	}
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mukdycphq9tqiv813dcy.png)

[Repo com mais exemplos](https://github.com/daienelima/exemplo-HATEOAS)