Comenzando con Mockito @Mock, @Spy, @Captor y @InjectMocks

1. Información general

En este tutorial, cubriremos las anotaciones de la biblioteca de Mockito : @Mock , @Spy , @Captor y @InjectMocks .

Para obtener más bondad de Mockito, eche un vistazo a la serie aquí.

2. Habilita las anotaciones de Mockito

Antes de continuar, exploremos diferentes formas de habilitar el uso de anotaciones con las pruebas de Mockito.

2.1. MockitoJUnitRunner

La primera opción que tenemos es anotar la prueba JUnit con un MockitoJUnitRunner como en el siguiente ejemplo:

@RunWith(MockitoJUnitRunner.class) public class MockitoAnnotationTest { ... }

2.2. MockitoAnnotations.initMocks ()

Alternativamente, también podemos habilitar las anotaciones de Mockito mediante programación , invocando MockitoAnnotations.initMocks () :

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

2.3. MockitoJUnit.rule ()

Por último, podemos usar un MockitoJUnit.rule () como se muestra a continuación:

public class MockitoInitWithMockitoJUnitRuleUnitTest { @Rule public MockitoRule initRule = MockitoJUnit.rule(); ... }

En este caso, debemos recordar hacer pública nuestra regla .

3. @ Anotación simulada

La anotación más utilizada en Mockito es @Mock . Podemos usar @Mock para crear e inyectar instancias simuladas sin tener que llamar a Mockito.mock manualmente.

En el siguiente ejemplo, crearemos una ArrayList simulada con la forma manual sin usar la anotación @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()); }

Y ahora haremos lo mismo, pero inyectaremos el simulacro usando la anotación @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 cómo, en ambos ejemplos, estamos interactuando con el simulacro y verificando algunas de estas interacciones, solo para asegurarnos de que el simulacro se está comportando correctamente.

4. @ Anotación de espía

Ahora, veamos cómo usar la anotación @Spy para espiar una instancia existente.

En el siguiente ejemplo, creamos un espía de una Lista con la forma anterior sin usar la anotación @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()); }

Ahora hagamos lo mismo, espíe la lista, pero hágalo usando la anotación @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 cómo, como antes, estamos interactuando con el espía aquí para asegurarnos de que se comporte correctamente. En este ejemplo nosotros:

  • Usó el método real spiedList.add () para agregar elementos a spiedList .
  • Aplicó el método spiedList.size () para devolver 100 en lugar de 2 usando Mockito.doReturn () .

5. @Captor Anotación

A continuación, veamos cómo usar la anotación @Captor para crear una instancia de ArgumentCaptor .

En el siguiente ejemplo, creamos un ArgumentCaptor con la forma anterior sin usar la anotación @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()); }

Ahora hagamos uso de @Captor para el mismo propósito: crear una instancia de ArgumentCaptor :

@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 cómo la prueba se vuelve más simple y legible cuando sacamos la lógica de configuración.

6. @InjectMocks Anotación

Ahora, analicemos cómo usar la anotación @InjectMocks para inyectar campos simulados en el objeto probado automáticamente.

En el siguiente ejemplo, usamos @InjectMocks para inyectar el mapa de palabras simulado en el dic MyDictionary :

@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")); }

Y aquí está la clase MyDictionary :

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. Inyectando un simulacro en un espía

De manera similar a la prueba anterior, es posible que deseemos inyectar un simulacro en un espía:

@Mock Map wordMap; @Spy MyDictionary spyDic = new MyDictionary();

Sin embargo, Mockito no admite inyectar simulacros en espías, y la siguiente prueba da como resultado una excepción:

@Test public void whenUseInjectMocksAnnotation_thenCorrect() { Mockito.when(wordMap.get("aWord")).thenReturn("aMeaning"); assertEquals("aMeaning", spyDic.getMeaning("aWord")); }

Si queremos usar un simulacro con un espía, podemos inyectarlo manualmente a través de un constructor:

MyDictionary(Map wordMap) { this.wordMap = wordMap; }

En lugar de usar la anotación, ahora podemos crear el espía manualmente:

@Mock Map wordMap; MyDictionary spyDic; @Before public void init() { MockitoAnnotations.initMocks(this); spyDic = Mockito.spy(new MyDictionary(wordMap)); } 

La prueba ahora pasará.

8. Ejecutar NPE mientras se usa la anotación

A menudo, podemos encontrarnos con NullPointerException cuando intentamos usar la instancia anotada con @Mock o @Spy :

public class MockitoAnnotationsUninitializedUnitTest { @Mock List mockedList; @Test(expected = NullPointerException.class) public void whenMockitoAnnotationsUninitialized_thenNPEThrown() { Mockito.when(mockedList.size()).thenReturn(1); } }

La mayoría de las veces, esto sucede simplemente porque nos olvidamos de habilitar correctamente las anotaciones de Mockito.

Entonces, tenemos que tener en cuenta que cada vez que queremos usar anotaciones de Mockito, debemos dar un paso más e inicializarlas como ya explicamos anteriormente.

9. Notas

Finalmente, aquí hay algunas notas sobre las anotaciones de Mockito:

  • Las anotaciones de Mockito minimizan el código repetitivo de creación de simulacros
  • Hacen que las pruebas sean más legibles
  • @InjectMocks es necesario para inyectar instancias de @Spy y @Mock

10. Conclusión

En este tutorial rápido, mostramos los conceptos básicos de las anotaciones en la biblioteca de Mockito .

La implementación de todos estos ejemplos se puede encontrar en GitHub. Este es un proyecto de Maven, por lo que debería ser fácil de importar y ejecutar tal como está.

Y por supuesto, para más bondad de Mockito, echa un vistazo a la serie aquí.