Introdução ao Mockito @Mock, @Spy, @Captor e @InjectMocks
1. Visão geral
Neste tutorial, cobriremosannotations of the Mockito library -@Mock,@Spy,@Captor e@InjectMocks.
Para obter mais vantagens do Mockito,have a look at the series here.
Leitura adicional:
Mockito - Usando espiões
Fazendo bom uso de espiões em Mockito e como os espiões são diferentes de zombarias.
EasyMock vs Mockito vs JMockit
Um guia rápido e prático para entender e comparar as bibliotecas de simulação em Java.
Injeção de mockock Mockito nos feijões da primavera
Este artigo mostrará como usar a injeção de dependência para inserir zombarias Mockito no Spring Beans para teste de unidade.
2. Ativar anotações Mockito
Primeiro - vamos ver como habilitar o uso de anotações com testes Mockito.
Para que essas anotações sejam habilitadas, precisaremosannotate the JUnit test with a runner -MockitoJUnitRunner como no exemplo a seguir:
@RunWith(MockitoJUnitRunner.class)
public class MockitoAnnotationTest {
...
}
Como alternativa, podemosenable these annotations programmatically também, invocandoMockitoAnnotations.initMocks() como no exemplo a seguir:
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
3. @Mock Anotação
A anotação amplamente usada mais usada no Mockito é@Mock. Podemos usar@Mock para criar e injetar instâncias simuladas sem ter que chamarMockito.mock manualmente.
No exemplo a seguir - criaremos umArrayList simulado com a maneira manual sem usar a anotação@Mock:
@Test
public void whenNotUseMockAnnotation_thenCorrect() {
List mockList = Mockito.mock(ArrayList.class);
mockList.add("one");
Mockito.verify(mockList).add("one");
assertEquals(0, mockList.size());
Mockito.when(mockList.size()).thenReturn(100);
assertEquals(100, mockList.size());
}
E agora faremos o mesmo, mas injetaremos a simulação usando a anotação@Mock:
@Mock
List mockedList;
@Test
public void whenUseMockAnnotation_thenMockIsInjected() {
mockedList.add("one");
Mockito.verify(mockedList).add("one");
assertEquals(0, mockedList.size());
Mockito.when(mockedList.size()).thenReturn(100);
assertEquals(100, mockedList.size());
}
Observe como - em ambos os exemplos, estamos interagindo com a simulação e verificando algumas dessas interações - apenas para ter certeza de que a simulação está se comportando corretamente.
4. @Spy Anotação
Agora - vamos ver como usar a anotação@Spy para espionar uma instância existente.
No exemplo a seguir - criamos um espião deList com a maneira antiga sem usar a anotação@Spy:
@Test
public void whenNotUseSpyAnnotation_thenCorrect() {
List spyList = Mockito.spy(new ArrayList());
spyList.add("one");
spyList.add("two");
Mockito.verify(spyList).add("one");
Mockito.verify(spyList).add("two");
assertEquals(2, spyList.size());
Mockito.doReturn(100).when(spyList).size();
assertEquals(100, spyList.size());
}
Agora vamos fazer o mesmo - espionar a lista - mas fazer isso usando a anotação@Spy:
@Spy
List spiedList = new ArrayList();
@Test
public void whenUseSpyAnnotation_thenSpyIsInjectedCorrectly() {
spiedList.add("one");
spiedList.add("two");
Mockito.verify(spiedList).add("one");
Mockito.verify(spiedList).add("two");
assertEquals(2, spiedList.size());
Mockito.doReturn(100).when(spiedList).size();
assertEquals(100, spiedList.size());
}
Observe como, como antes, estamos interagindo com o espião aqui para garantir que ele se comporte corretamente. Neste exemplo, nós:
-
Usou o métodorealspiedList.add() para adicionar elementos aspiedList.
-
Stubbed o métodospiedList.size() para retornar100 em vez de2 usandoMockito.doReturn().
5. @Captor Anotação
A seguir - vamos ver como usar a anotação@Captor para criar uma instânciaArgumentCaptor.
No exemplo a seguir - criamos umArgumentCaptor com a maneira antiga sem usar a anotação@Captor:
@Test
public void whenNotUseCaptorAnnotation_thenCorrect() {
List mockList = Mockito.mock(List.class);
ArgumentCaptor arg = ArgumentCaptor.forClass(String.class);
mockList.add("one");
Mockito.verify(mockList).add(arg.capture());
assertEquals("one", arg.getValue());
}
Vamos agoramake use of @Captor com o mesmo propósito - para criar uma instânciaArgumentCaptor:
@Mock
List mockedList;
@Captor
ArgumentCaptor argCaptor;
@Test
public void whenUseCaptorAnnotation_thenTheSam() {
mockedList.add("one");
Mockito.verify(mockedList).add(argCaptor.capture());
assertEquals("one", argCaptor.getValue());
}
Observe como o teste se torna mais simples e mais legível quando adotamos a lógica de configuração.
6. @InjectMocks Anotação
Agora - vamos discutir como usar a anotação@InjectMocks - para injetar campos fictícios no objeto testado automaticamente.
No exemplo a seguir - usamos@InjectMocks para injetarwordMap simulado emMyDictionarydic:
@Mock
Map wordMap;
@InjectMocks
MyDictionary dic = new MyDictionary();
@Test
public void whenUseInjectMocksAnnotation_thenCorrect() {
Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning");
assertEquals("aMeaning", dic.getMeaning("aWord"));
}
E aqui está a classeMyDictionary:
public class MyDictionary {
Map wordMap;
public MyDictionary() {
wordMap = new HashMap();
}
public void add(final String word, final String meaning) {
wordMap.put(word, meaning);
}
public String getMeaning(final String word) {
return wordMap.get(word);
}
}
7. Injetando um mock em um espião
Semelhante ao teste acima, podemos querer injetar uma simulação em um espião:
@Mock
Map wordMap;
@Spy
MyDictionary spyDic = new MyDictionary();
However, Mockito doesn’t support injecting mocks into spies,e os seguintes resultados de teste em uma exceção:
@Test
public void whenUseInjectMocksAnnotation_thenCorrect() {
Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning");
assertEquals("aMeaning", spyDic.getMeaning("aWord"));
}
Se queremos usar um mock com um espião, podemos injetar manualmente o mock através de um construtor:
MyDictionary(Map wordMap) {
this.wordMap = wordMap;
}
Em vez de usar a anotação, agora podemos criar o espião manualmente:
@Mock
Map wordMap;
MyDictionary spyDic;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
spyDic = Mockito.spy(new MyDictionary(wordMap));
}
O teste agora será aprovado.
8. Executando no NPE ao usar a anotação __
Freqüentemente, podemosrun into NullPointerException quando realmente tentamos usar a instância anotada com@Mockor@Spy, como no exemplo:
public class NPETest {
@Mock
List mockedList;
@Test
public void test() {
Mockito.when(mockedList.size()).thenReturn(1);
}
}
Na maioria das vezes isso acontece simplesmente porque esquecemos de ativar corretamente as anotações do Mockito.
Portanto, devemos ter em mente que, sempre que queremos usar as anotações do Mockito, devemos dar um passo extra e inicializá-las, como já explicamos anteriormente.
9. Notas
Finalmente - aqui estãosome notes sobre as anotações Mockito:
-
Use anotações para minimizar o código repetitivo de criação simulada
-
Use anotações para tornar o teste mais legível
-
Use@InjectMocks para injetar instâncias de@Spy e@Mock
10. Conclusão
Neste tutorial rápido, mostramos o básico deannotations in the Mockito library.
A implementação de todos esses exemplos pode ser encontradaover on GitHub. Como é um projeto do Maven, deve ser fácil importar e executar como está.
E, claro, para obter mais vantagens do Mockito,have a look at the series here.