Comenzando con Mockito

Agregar comportamiento al objeto simulado

Mockito.when(mock.returnSomething()).thenReturn("my val");

mock.returnSomething(); // returns "my val"
mock.returnSomething(); // returns "my val" again
mock.returnSomething(); // returns "my val" again and again and again...

Si desea un valor diferente en la segunda llamada, puede agregar el argumento de retorno deseado al método thenReturn:

Mockito.when(mock.returnSomething()).thenReturn("my val", "other val");

mock.returnSomething(); // returns "my val"
mock.returnSomething(); // returns "other val"
mock.returnSomething(); // returns "other val" again

Si llamará al método sin agregar un comportamiento para simular, devolverá un valor nulo:

barMock.mock.returnSomethingElse(); // returns null

En caso de que el método simulado tenga parámetros, también debe declarar valores:

Mockito.when(mock.returnSomething("param 1")).thenReturn("my val 1");
Mockito.when(mock.returnSomething("param 2")).thenReturn("my val 2");

mock.returnSomething("param 1"); // returns "my val 1"
mock.returnSomething("param 2"); // returns "my val 2"
mock.returnSomething("param 3"); // returns null

Si no le importa el valor del parámetro, puede usar Matchers.any():

Mockito.when(mock.returnSomething(Matchers.any())).thenReturn("p1");

mock.returnSomething("param 1"); // returns "p1"
mock.returnSomething("param other"); // returns "p1"

Para lanzar una excepción, use el método thenThrow:

Mockito.when(mock.returnSomething()).thenThrow(new Exception());

mock.returnSomething(); // throws Exception

Crear objetos burlados por Mockito

Hay dos formas de crear un objeto burlado por Mockito:

  • a través de la anotación
  • a través de la función simulada

Mediante anotación:

Con un corredor de prueba JUnit:

@RunWith(MockitoJUnitRunner.class)
public class FooTest {
    @Mock
    private Bar barMock;

    // ...
}

También puede usar JUnit @Rule de Mockito, que proporciona la misma funcionalidad que MockitoJUnitRunner, pero no necesita un corredor de prueba @RunWith:

public class FooTest {
    @Rule
    public MockitoRule mockito = MockitoJUnit.rule();        

    @Mock
    private Bar barMock;

    // ...
}

Si no puede usar @RunWith o la anotación @Rule, también puede iniciar simulacros “por mano”:

public class FooTest {
    @Mock
    private Bar barMock;

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

    // ...
}

A través de la función simulada:

public class FooTest {
    private Bar barMock = Mockito.mock(Bar.class);

    // ...
}

Debido al borrado de tipo, no puede simular una clase genérica como se indicó anteriormente. Debe simular la clase base y convertir explícitamente al tipo genérico correcto:

public class FooTest {
    private Bar<String> genericBarMock = (Bar<String>) Mockito.mock(Bar.class);

    // ...
}

Verificar las llamadas al método en el objeto simulado

Para verificar si se llamó a un método en un objeto simulado, puede usar el método Mockito.verify:

Mockito.verify(someMock).bla();

En este ejemplo, afirmamos que el método bla fue llamado en el objeto simulado someMock.

También puede verificar si se llamó a un método con ciertos parámetros:

Mockito.verify(someMock).bla("param 1");

Si desea verificar que un método no fue llamado, puede pasar un parámetro VerificationMode adicional a verify:

Mockito.verify(someMock, Mockito.times(0)).bla();

Esto también funciona si desea verificar que este método se haya llamado más de una vez (en este caso, verificamos que el método bla se haya llamado 23 veces):

Mockito.verify(someMock, Mockito.times(23)).bla();

Estos son más ejemplos del parámetro VerificationMode, que brindan más control sobre la cantidad de veces que se debe llamar a un método:

Mockito.verify(someMock, Mockito.never()).bla(); // same as Mockito.times(0)

Mockito.verify(someMock, Mockito.atLeast(3)).bla(); // min 3 calls

Mockito.verify(someMock, Mockito.atLeastOnce()).bla(); // same as Mockito.atLeast(1)

Mockito.verify(someMock, Mockito.atMost(3)).bla(); // max 3 calls

Prueba unitaria simple usando Mockito

La clase que vamos a probar es:

public class Service {

    private Collaborator collaborator;

    public Service(Collaborator collaborator) {
        this.collaborator = collaborator;
    }
    
    public String performService(String input) {
        return collaborator.transformString(input);
    }
}

Su colaborador es:

public class Collaborator {

    public String transformString(String input) {
        return doStuff();
    }

    private String doStuff() {
        // This method may be full of bugs
        . . .
        return someString;
    }

}

En nuestra prueba, queremos romper la dependencia de Colaborador y sus errores, por lo que vamos a burlarnos de Colaborador:

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import org.junit.Test;

public class ServiceTest {
    @Test
    public void testPerformService() throws Exception {
        // Configure mock
        Collaborator collaboratorMock = mock(Collaborator.class);
        doReturn("output").when(collaboratorMock).transformString("input");

        // Perform the test
        Service service = new Service(collaboratorMock);
        String actual = service.performService("input");
        
        // Junit asserts
        String expected = "output";
        assertEquals(expected, actual);
    }  
}

Usar anotaciones de Mockito

La clase que vamos a probar es:

public class Service{

    private Collaborator collaborator;

    public Service(Collaborator collaborator){
        this.collaborator = collaborator;
    }
    
    
    public String performService(String input){
        return collaborator.transformString(input);
    }
}

Su colaborador es:

public class Collaborator {

    public String transformString(String input){
        return doStuff();
    }

    private String doStuff()
    {
        // This method may be full of bugs
        . . .
        return someString;
    }

}

En nuestra prueba, queremos romper la dependencia de Colaborador y sus errores, por lo que vamos a burlarnos de Colaborador. Usar la anotación @Mock es una forma conveniente de crear diferentes instancias de simulacros para cada prueba:

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.InjectMocks;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class ServiceTest {

    @Mock
    private Collaborator collaboratorMock;

    @InjectMocks
    private Service service;
    
    @Test
    public void testPerformService() throws Exception {
        // Configure mock
        doReturn("output").when(collaboratorMock).transformString("input");            

        // Perform the test
        String actual = service.performService("input");
        
        // Junit asserts
        String expected = "output";
        assertEquals(expected, actual);
    }
    
    
    @Test(expected=Exception.class)
    public void testPerformServiceShouldFail() throws Exception {
        // Configure mock
        doThrow(new Exception()).when(collaboratorMock).transformString("input");

        // Perform the test
        service.performService("input");
    }
}

Mockito intentará resolver la inyección de dependencia en el siguiente orden:

  1. Inyección basada en constructor: los simulacros se inyectan en el constructor con la mayoría de los argumentos (si no se pueden encontrar algunos argumentos, se pasan valores nulos). Si un objeto se creó con éxito a través del constructor, no se aplicarán otras estrategias.
  2. Inyección basada en setter: los simulacros se inyectan por tipo. Si hay varias propiedades del mismo tipo, los nombres de propiedad y los nombres simulados coincidirán.
  3. Inyección de campo directa: igual que para la inyección basada en setter.

Tenga en cuenta que no se informa de ningún fallo en caso de que falle alguna de las estrategias antes mencionadas.

Consulte el último @InjectMocks para obtener información más detallada sobre este mecanismo en la última versión de Mockito.

Instalación y configuración

Instalación

La forma preferida de instalar Mockito es declarar una dependencia en mockito-core con un sistema de construcción de elección. A partir del 22 de julio de 2016, la última versión no beta es 1.10.19, pero 2.x ya se recomienda migrar a.

Maven

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>1.10.19</version>
    <scope>test</scope>
</dependency>

Gradle

repositories { jcenter() }
dependencies { testCompile "org.mockito:mockito-core:1.+" }

También hay mockito-all que contiene Hamcrest y Objenesis además del propio Mockito. Se entrega a través de Maven principalmente para usuarios de hormigas, pero la distribución se suspendió en Mockito 2.x.


Importar

La mayoría de las instalaciones de Mockito son métodos estáticos de org.mockito.Mockito. Por lo tanto, Mockito se puede importar estáticamente a una clase de esta manera:

import static org.mockito.Mockito.*;

El punto de entrada de la documentación se encuentra en el javadoc de esta clase.

Simular algunos métodos en un objeto

Prueba mínima simple de Mockito

Este ejemplo muestra una prueba mínima de Mockito utilizando una ArrayList simulada:

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

import java.util.ArrayList;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest
{
    @Mock
    ArrayList<String> listMock;

    @Test
    public void testAppend() {
        // configure the mock to return "foobar" whenever "get()" 
        // is called on "listMock" with an int value as parameter
        doReturn("foobar").when(listMock).get(anyInt());            
        String result = listMock.get(0);
        
        assertEquals("foobar", result);
    }
}

Verificando argumentos con ArgumentCaptor

Para validar los argumentos de los métodos llamados en un simulacro, use la clase ArgumentCaptor. Esto le permitirá extraer los argumentos en su método de prueba y realizar afirmaciones sobre ellos.

Este ejemplo prueba un método que actualiza el nombre de un usuario con una ID determinada. El método carga al usuario, actualiza el atributo name con el valor dado y luego lo guarda. La prueba quiere verificar que el argumento pasado al método save sea un objeto Usuario con el ID y el nombre correctos.

// This is mocked in the test
interface UserDao {
    void save(User user);
}

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
    @Mock
    UserDao userDao;

    @Test
    public void testSetNameForUser() {
        UserService serviceUnderTest = new UserService(userDao);
        
        serviceUnderTest.setNameForUser(1L, "John");

        ArgumentCaptor<User> userArgumentCaptor = ArgumentCaptor.forClass(User.class);
        
        verify(userDao).save(userArgumentCaptor.capture());
        User savedUser = userArgumentCaptor.getValue();
        assertTrue(savedUser.getId() == 1);
        assertTrue(savedUser.getName().equals("John"));
    }
}

Verificación de argumentos con ArgumentMatcher

Mockito proporciona una interfaz Matcher<T> junto con una clase abstracta ArgumentMatcher<T> para verificar los argumentos. Utiliza un enfoque diferente para el mismo caso de uso que ArgumentCaptor. Además, el ArgumentMatcher también se puede usar para burlarse. Ambos casos de uso hacen uso del método Mockito.argThat() que proporciona un código de prueba razonablemente legible.

verify(someMock).someMethod(Mockito.argThat(new ArgumentMatcher<String>() {
       
    @Override
    public boolean matches(Object o) {
        return o instanceof String && !((String)o).isEmpty();
    }

});        

De los JavaDocs de ArgumentMatcher:

Advertencia: Sea razonable con el uso de coincidencias de argumentos complicadas, especialmente comparadores de argumentos personalizados, ya que puede hacer que la prueba sea menos legible. A veces es mejor implementar equals() para los argumentos que se pasan a los simulacros (Mockito, naturalmente, usa equals() para la coincidencia de argumentos). Esto puede hacer que la prueba sea más limpia.

Métodos de anulación de stubbing

Comprobar los argumentos pasados ​​para simular