Hacer que un método simulado devuelva un argumento que se le pasó

Resuelto Abhijeet Kashnia asked hace 14 años • 10 respuestas

Considere una firma de método como:

public String myFunction(String abc);

¿Puede Mockito ayudar a devolver la misma cadena que recibió el método?

Abhijeet Kashnia avatar Apr 21 '10 23:04 Abhijeet Kashnia
Aceptado

Desde Mockito 1.9.5+ y Java 8+

Puedes usar una expresión lambda, como:

when(myMock.myFunction(anyString())).thenAnswer(i -> i.getArguments()[0]);

¿Dónde ihay una instancia de InvocationOnMock.

Para versiones anteriores

Puedes crear una respuesta en Mockito. Supongamos que tenemos una interfaz llamada MyInterface con un método myFunction.

public interface MyInterface {
    public String myFunction(String abc);
}

Aquí está el método de prueba con una respuesta Mockito:

public void testMyFunction() throws Exception {
    MyInterface mock = mock(MyInterface.class);
    when(mock.myFunction(anyString())).thenAnswer(new Answer<String>() {
    @Override
    public String answer(InvocationOnMock invocation) throws Throwable {
        Object[] args = invocation.getArguments();
        return (String) args[0];
    }
    });

    assertEquals("someString",mock.myFunction("someString"));
    assertEquals("anotherString",mock.myFunction("anotherString"));
}
Steve avatar Apr 26 '2010 06:04 Steve

Si tiene Mockito 1.9.5 o superior, hay un nuevo método estático que puede crear el Answerobjeto por usted. Necesitas escribir algo como

import static org.mockito.Mockito.when;
import static org.mockito.AdditionalAnswers.returnsFirstArg;

when(myMock.myFunction(anyString())).then(returnsFirstArg());

o alternativamente

doAnswer(returnsFirstArg()).when(myMock).myFunction(anyString());

Tenga en cuenta que el returnsFirstArg()método es estático en la AdditionalAnswersclase, lo cual es nuevo en Mockito 1.9.5; entonces necesitarás la importación estática correcta.

Dawood ibn Kareem avatar Aug 07 '2012 06:08 Dawood ibn Kareem

Con Java 8 es posible crear una respuesta de una línea incluso con una versión anterior de Mockito:

when(myMock.myFunction(anyString()).then(i -> i.getArgumentAt(0, String.class));

Por supuesto, esto no es tan útil como el uso AdditionalAnswerssugerido por David Wallace, pero podría ser útil si desea transformar un argumento "sobre la marcha".

Paweł Dyda avatar Feb 04 '2015 20:02 Paweł Dyda

Con Java 8, la respuesta de Steve puede ser

public void testMyFunction() throws Exception {
    Application mock = mock(Application.class);
    when(mock.myFunction(anyString())).thenAnswer(
    invocation -> {
        Object[] args = invocation.getArguments();
        return args[0];
    });

    assertEquals("someString", mock.myFunction("someString"));
    assertEquals("anotherString", mock.myFunction("anotherString"));
}

EDITAR: Aún más corto:

public void testMyFunction() throws Exception {
    Application mock = mock(Application.class);
    when(mock.myFunction(anyString())).thenAnswer(
        invocation -> invocation.getArgument(0));

    assertEquals("someString", mock.myFunction("someString"));
    assertEquals("anotherString", mock.myFunction("anotherString"));
}
yiwei avatar Jul 24 '2015 04:07 yiwei

Tuve un problema muy similar. El objetivo era burlarse de un servicio que persiste Objetos y puede devolverlos por su nombre. El servicio se ve así:

public class RoomService {
    public Room findByName(String roomName) {...}
    public void persist(Room room) {...}
}

El simulacro de servicio utiliza un mapa para almacenar las instancias de Room.

RoomService roomService = mock(RoomService.class);
final Map<String, Room> roomMap = new HashMap<String, Room>();

// mock for method persist
doAnswer(new Answer<Void>() {
    @Override
    public Void answer(InvocationOnMock invocation) throws Throwable {
        Object[] arguments = invocation.getArguments();
        if (arguments != null && arguments.length > 0 && arguments[0] != null) {
            Room room = (Room) arguments[0];
            roomMap.put(room.getName(), room);
        }
        return null;
    }
}).when(roomService).persist(any(Room.class));

// mock for method findByName
when(roomService.findByName(anyString())).thenAnswer(new Answer<Room>() {
    @Override
    public Room answer(InvocationOnMock invocation) throws Throwable {
        Object[] arguments = invocation.getArguments();
        if (arguments != null && arguments.length > 0 && arguments[0] != null) {
            String key = (String) arguments[0];
            if (roomMap.containsKey(key)) {
                return roomMap.get(key);
            }
        }
        return null;
    }
});

Ahora podemos ejecutar nuestras pruebas en este simulacro. Por ejemplo:

String name = "room";
Room room = new Room(name);
roomService.persist(room);
assertThat(roomService.findByName(name), equalTo(room));
assertNull(roomService.findByName("none"));
migu avatar Jul 19 '2011 11:07 migu

Esta es una pregunta bastante antigua, pero creo que sigue siendo relevante. Además, la respuesta aceptada funciona solo para String. Mientras tanto, existe Mockito 2.1 y algunas importaciones han cambiado, así que me gustaría compartir mi respuesta actual:

import static org.mockito.AdditionalAnswers.returnsFirstArg;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

@Mock
private MyClass myClass;

// this will return anything you pass, but it's pretty unrealistic
when(myClass.myFunction(any())).then(returnsFirstArg());
// it is more "life-like" to accept only the right type
when(myClass.myFunction(any(ClassOfArgument.class))).then(returnsFirstArg());

myClass.myFunction se vería así:

public class MyClass {
    public ClassOfArgument myFunction(ClassOfArgument argument){
        return argument;
    }  
}
LazR avatar Feb 28 '2019 09:02 LazR