Resumão Mockito 3
utilizando Java 11 e JUnit 5
Código fonte único com as principais funcionalidades do Mockito 3.
Conteúdo
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dev.caiosantesso</groupId>
<artifactId>resumao-mockito</artifactId>
<version>2021.4.0</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>3.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<!-- Necessário para executar 'mvn test' com JUnit 5 -->
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
</project>
Mockito 3
package dev.caiosantesso;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.IntSupplier;
import java.util.stream.IntStream;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Mockito.*;
// Classe que servirá de mock. A implementação será ignorada.
class Inacabada {
static String estatico() {
return "método estático";
}
int quinze() {
return 15;
}
double pi() {
return Math.PI;
}
boolean verdadeiro() {
return true;
}
String frase() {
return "Mockito";
}
List<Number> colecao() {
return List.of(quinze(), pi(), 23);
}
void receba(String string) {
}
void receba(Number numero) {
}
void receba2(String string, List<Integer> lista) {
}
int tamanho(Collection<String> colecao) {
return colecao.size();
}
long tamanho(IntSupplier gerador) {
return IntStream.generate(gerador).limit(1).count();
}
}
//Classe que utiliza o mock.
class Regular {
private Inacabada classe;
void quinzeSeVerdadeiroSeNaoFrase() {
if (classe.verdadeiro())
classe.quinze();
else
classe.frase();
}
void definaArgs() {
classe.receba("ABC");
classe.receba2("Qualquer", List.of(7, 8, 9));
}
void repitaXVezes(int x) {
for (int i = 0; i < x && classe.pi() == 0.0; i++) {
classe.receba(i);
}
definaArgs();
}
double obtenhaPi() {
return classe.pi();
}
int dobroDoTamanho(Collection<String> colecao) {
return classe.tamanho(colecao) * 2;
}
long triploDoTamanhoDeUmStreamDeUmElemento() {
long tamanho = classe.tamanho(() -> 7);
return tamanho * 3;
}
}
// Necessário para utilizar anotações como @Mock e @InjectMocks.
@ExtendWith(MockitoExtension.class)
public class ResumaoMockitoTest {
// As chamadas aos métodos da classe Inacabada devolverão
// 0/false/null na falta de stubbings. A implementação não é
// executada.
@Mock
Inacabada meuMock;
// Injeta a classe Inacabada no campo de Regular.
// Inacabada poderia ser injetada também por construtor ou setter.
@InjectMocks
Regular regular;
@Test
void toStringDeMocksDevolvemONomeDaVariavel() {
assertEquals("meuMock", meuMock.toString());
}
@Test
void metodosDeMockDevolvemZeroOuFalsoOuNullOuColecaoVazia() {
assertEquals(0, meuMock.quinze());
assertEquals(0.0, meuMock.pi());
assertFalse(meuMock.verdadeiro());
assertNull(meuMock.frase());
assertIterableEquals(Collections.emptyList(),
meuMock.colecao());
}
@Test
void verifyVerificaSeMetodoFoiChamadoUmaVez() {
regular.quinzeSeVerdadeiroSeNaoFrase();
// Verifica se verdadeiro() e frase() foram chamados uma vez.
verify(meuMock).frase();
verify(meuMock).verdadeiro();
}
@Test
void verifyTambemVerificaSeMetodoFoiChamadoNenhumaOuVariasVezes() {
// Iterará todas as 10 vezes pois pi() sempre retornará 0.
regular.repitaXVezes(10);
// verify() verifica que...
// ...pi() foi chamado exatamente 10 vezes.
verify(meuMock, times(10)).pi();
// ...frase() nunca foi executado.
verify(meuMock, never()).frase();
// ...receba() com o argumento 5 foi chamado no máximo uma
// vez.
verify(meuMock, atMostOnce()).receba(5);
// ...receba() com o argumento 6 foi chamado exatamente uma
// vez.
verify(meuMock).receba(6);
verify(meuMock).receba("ABC");
}
@Test
void verifyNoMoreInteractionsVerificaSeTodosOsMetodosDoMockChamadosForamVerificados() {
regular.repitaXVezes(1);
verify(meuMock).pi();
verify(meuMock).receba(0);
verify(meuMock).receba("ABC");
verify(meuMock).receba2("Qualquer", List.of(7, 8, 9));
verifyNoMoreInteractions(meuMock);
}
@Test
void argumentMatchersSubstituemArgumentos() {
int x = 5;
regular.repitaXVezes(x);
// Verifica que receba() foi chamado 5 vezes com qualquer
// inteiro como argumento.
verify(meuMock, times(x)).receba(anyInt());
// Ambos verificam se o argumento de receba() é do tipo
// Number ou um de seus subtipos.
verify(meuMock, times(x)).receba(any(Number.class));
verify(meuMock, times(x)).receba(isA(Number.class));
// Verifica que receba() foi chamado 5 vezes com um
// argumento 0 ou maior.
verify(meuMock, times(x)).receba(intThat(i -> i > -1));
// Métodos xxxThat() aceitam lambdas que retornam booleano,
// denotando alguma condição.
// Verifica que receba() foi chamado 1 vez com um argumento
// contendo 'B'.
verify(meuMock).receba(contains("B"));
// Nenhum ou todos os argumentos devem ser ArgumentMatchers
// por isso eq() é necessário abaixo.
verify(meuMock).receba2(eq("Qualquer"), isNotNull());
// 1. eq() verifica que o primeiro arg de receba2() foi
// 'Qualquer'.
// 2. isNotNull() certifica que o segundo arg recebido por
// receba2() não é nulo.
verify(meuMock).receba2(startsWith("Qu"),
argThat(list -> list.size() == 3));
}
@Test
void argumentCaptorVerificaOsArgumentosUtilizadosNaChamadaDeUmMetodo() {
regular.repitaXVezes(3);
// Especifica o tipo de argumento a ser capturado.
ArgumentCaptor<Integer> argumento =
ArgumentCaptor.forClass(Integer.class);
// Verifica que receba() foi chamado 3 vezes e captura os 3
// args utilizados anteriormente.
verify(meuMock, times(3)).receba(argumento.capture());
// getAllValues() traz uma lista com todos os argumentos
// capturados.
assertIterableEquals(List.of(0, 1, 2),
argumento.getAllValues());
// getValue() traz o último argumento capturado.
assertEquals(2, argumento.getValue());
assertEquals(2, argumento.getValue());
}
@Test
void inOrderVerificaChamadasNaOrdemCorreta() {
regular.repitaXVezes(3);
InOrder emOrdem = inOrder(meuMock);
emOrdem.verify(meuMock).receba(0);
emOrdem.verify(meuMock).receba(1);
emOrdem.verify(meuMock).receba(2);
}
@Test
public void whenCriaStubsQueSaoMetodosComOValorDevolvidoPreDefinido() {
// Quando pi() for chamado, 9.99 será devolvido. A
// implementação no mock é substituída.
when(meuMock.pi()).thenReturn(9.99D);
double naoPi = regular.obtenhaPi();
assertEquals(9.99D, naoPi, 0.1);
assertEquals(9.99D, meuMock.pi(), 0.1);
}
@Test
public void argumentoDoStubDeveSerIgualAoDaChamadaNaImplementacao() {
var lista = List.of("A");
var outraLista = Collections.singletonList("A");
assertEquals(lista, outraLista);
when(meuMock.tamanho(lista)).thenReturn(22);
int dobroDoTamanho = regular.dobroDoTamanho(outraLista);
// Como tamanho() foi configurado no when(), quando tamanho
// () é chamado dentro de
// dobroDoTamanho() e os argumentos são iguais então
// thenReturn() devolve o valor (22).
assertEquals(44, dobroDoTamanho);
var conjunto = Set.of("A");
assertNotEquals(lista, conjunto);
// Como tamanho() em dobroDoTamanho() abaixo não tem stub 0
// será devolvido.
int zeroDeTamanho = regular.dobroDoTamanho(conjunto);
assertEquals(0, zeroDeTamanho);
}
@Test
public void stubbingsPodemUtilizarArgumentMatchers() {
when(meuMock.tamanho(anyCollection())).thenReturn(5);
int tamanho1 = regular.dobroDoTamanho(Set.of("Z", "T", "R"));
int tamanho2 =
regular.dobroDoTamanho(Collections.singleton("X"));
assertEquals(10, tamanho1);
assertEquals(10, tamanho2);
}
@Test
public void thenReturnTambemDevolveListaDeValores() {
// O valor é devolvido conforme a vez que pi() é chamado.
when(meuMock.pi()).thenReturn(9.99D, 7.23D, 0.15D);
assertEquals(9.99D, regular.obtenhaPi(), 0.1);
assertEquals(7.23D, regular.obtenhaPi(), 0.1);
assertEquals(0.15D, regular.obtenhaPi(), 0.1);
// Quando a lista de retornos é exaurida, o último sempre
// será devolvido.
assertEquals(0.15D, regular.obtenhaPi(), 0.1);
}
@Test
public void thenThrowLancaExcecoesNaoChecadas() {
Class<NullPointerException> npe = NullPointerException.class;
when(meuMock.pi()).thenThrow(npe);
assertThrows(npe, () -> regular.obtenhaPi());
// doThrow() é a versão para método que não tem tipo de
// retorno (void).
doThrow(npe).when(meuMock).receba(anyString());
assertThrows(npe, () -> regular.definaArgs());
}
@Test
public void thenThrowEThenReturnPodemSerEncadeados() {
Class<IllegalStateException> illegalState =
IllegalStateException.class;
Class<NullPointerException> npe = NullPointerException.class;
when(meuMock.pi()).thenThrow(npe).thenReturn(9.99D)
.thenThrow(illegalState);
assertThrows(npe, () -> regular.obtenhaPi());
assertEquals(9.99D, regular.obtenhaPi(), 0.1);
assertThrows(illegalState, () -> regular.obtenhaPi());
}
@Test
public void lambdasPrecisamDeArgumentMatchersNosStubs() {
// Exemplificando que lambdas são apenas iguais a si.
IntSupplier a = () -> 7;
IntSupplier b = () -> 7;
assertNotEquals(a, b);
// ArgumentMatcher necessário já que arg só seria igual a
// si próprio.
when(meuMock.tamanho(any(IntSupplier.class))).thenReturn(5L);
long tamanho =
regular.triploDoTamanhoDeUmStreamDeUmElemento();
assertEquals(15, tamanho);
}
@Test
public void verificaoNoEstiloBDD() {
// given() é apelido para o when() utilizado para criar
// stubbings.
BDDMockito.given(meuMock.pi()).willReturn(4.2D);
// when
regular.obtenhaPi();
// then() é similar a verify().
BDDMockito.then(meuMock).should().pi();
}
}
Referências
Escrito por Caio Santesso.